Skip to content

Commit fa18348

Browse files
authored
Initial commit of LogService and HAKeeper (#2970)
* logservice: initial commit * logservice: added LogShardManager * logservice: renamed service.go -> shards.go * logservice: added hakeeper and tests * logservice: some cleanups * logservice: added stateMachine.LeaseHistory * logservice: added the ability to filter internal entries * logservice: fixed various issues in LogStore * logservice: updated store APIs to expose LogRecord and LSN * logservice: pass meta info to NodeHost * logservice: allow NodeHostID to be specified * logservice: added the ability to query serviceAddress * logservice: added the ability to query shard info * logservice: minor update * logservice: truncate log asynchronously in a worker goroutine * logservice: fixed copyright notice * logservice: added heartbeat message ready to be sent to HAKeeper * logservice: use gogofaster to generate .pb.go * logservice: minor update to reflect dragonboat v4 changes * logservice: added pb/rpc * logservice: added server side rpc support * logservice: bumped cube version to avoid pebble version conflicts * logservice: added error handling * logservice: more error handling * logservice: added some tests * logservice: minor fixess for errors.go * logservice: added DN heartbeat messages * logservice: minor cleanups * logservice: minor fix for error handling * logservice: moved hakeeper code to its own directory * logservice: made logservice rsm a IStateMachine * hakeeper: use Lookup() for querying shard ID * logservice: move pb file to matrixone/proto, some other cleanups * hakeeper: added hakeeper/state.go * logservice: added methods for updating hakeeper * hakeeper: minor fix, added some tests * logservice: added ticker for hakeeper replica * logservice: minor fix for service.go * logservice: fixed some issues in transport.go * logservice: added client.go * logservice: minor refactoring * logservice: added client_test.go, fixed a few bugs * logservice: readonly clients now reject write requests * logservice: refactored query shard info API * logservice: added tests for Servide.GetShardInfo * logservice: fixed a few static-check reported issues
1 parent 9ad4418 commit fa18348

27 files changed

+7609
-28
lines changed

go.mod

+25-10
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,17 @@ require (
1313
github.com/axiomhq/hyperloglog v0.0.0-20220105174342-98591331716a
1414
github.com/bxcodec/faker/v3 v3.8.0
1515
github.com/cespare/xxhash/v2 v2.1.2
16-
github.com/cockroachdb/pebble v0.0.0-20210526183633-dd2a545f5d75
16+
github.com/cockroachdb/pebble v0.0.0-20220407171941-2120d145e292
1717
github.com/fagongzi/goetty v1.13.0
1818
github.com/fagongzi/util v0.0.0-20210923134909-bccc37b5040d
1919
github.com/go-sql-driver/mysql v1.6.0
2020
github.com/gogo/protobuf v1.3.2
2121
github.com/golang/mock v1.6.0
2222
github.com/google/btree v1.0.1
2323
github.com/google/gofuzz v1.2.0
24-
github.com/matrixorigin/matrixcube v0.3.1-0.20220511071845-cfc4bac02bb4
24+
github.com/lni/dragonboat/v4 v4.0.0-20220604123758-e40bf3f57b59
25+
github.com/lni/goutils v1.3.1-0.20220604063047-388d67b4dbc4
26+
github.com/matrixorigin/matrixcube v0.3.1-0.20220606032431-c944d801f1e5
2527
github.com/matrixorigin/simdcsv v0.0.0-20210926114300-591bf748a770
2628
github.com/minio/minio-go/v7 v7.0.27
2729
github.com/panjf2000/ants/v2 v2.4.6
@@ -39,6 +41,8 @@ require (
3941
)
4042

4143
require (
44+
github.com/VictoriaMetrics/metrics v1.18.1 // indirect
45+
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da // indirect
4246
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.2 // indirect
4347
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.12 // indirect
4448
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.6 // indirect
@@ -47,15 +51,27 @@ require (
4751
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.7 // indirect
4852
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.6 // indirect
4953
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.6 // indirect
54+
github.com/getsentry/sentry-go v0.12.0 // indirect
5055
github.com/golang/protobuf v1.5.2 // indirect
51-
github.com/google/uuid v1.1.2 // indirect
56+
github.com/google/uuid v1.3.0 // indirect
57+
github.com/hashicorp/errwrap v1.0.0 // indirect
58+
github.com/hashicorp/go-immutable-radix v1.0.0 // indirect
59+
github.com/hashicorp/go-msgpack v0.5.3 // indirect
60+
github.com/hashicorp/go-multierror v1.0.0 // indirect
61+
github.com/hashicorp/go-sockaddr v1.0.0 // indirect
62+
github.com/hashicorp/golang-lru v0.5.1 // indirect
63+
github.com/hashicorp/memberlist v0.3.1 // indirect
5264
github.com/klauspost/cpuid v1.3.1 // indirect
53-
github.com/lni/goutils v1.3.0 // indirect
65+
github.com/miekg/dns v1.1.26 // indirect
5466
github.com/minio/md5-simd v1.1.0 // indirect
5567
github.com/minio/sha256-simd v0.1.1 // indirect
5668
github.com/mitchellh/go-homedir v1.1.0 // indirect
69+
github.com/pierrec/lz4/v4 v4.1.14 // indirect
5770
github.com/rs/xid v1.2.1 // indirect
71+
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect
5872
github.com/smartystreets/assertions v1.2.0 // indirect
73+
github.com/valyala/fastrand v1.1.0 // indirect
74+
github.com/valyala/histogram v1.2.0 // indirect
5975
gopkg.in/ini.v1 v1.57.0 // indirect
6076
)
6177

@@ -64,10 +80,9 @@ require (
6480
github.com/DataDog/zstd v1.5.0 // indirect
6581
github.com/beorn7/perks v1.0.1 // indirect
6682
github.com/bits-and-blooms/bitset v1.2.0 // indirect
67-
github.com/cockroachdb/errors v1.8.2 // indirect
68-
github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f // indirect
69-
github.com/cockroachdb/redact v1.0.8 // indirect
70-
github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2 // indirect
83+
github.com/cockroachdb/errors v1.9.0
84+
github.com/cockroachdb/logtags v0.0.0-20211118104740-dabe8e521a4f // indirect
85+
github.com/cockroachdb/redact v1.1.3 // indirect
7186
github.com/coreos/go-semver v0.3.0 // indirect
7287
github.com/coreos/go-systemd/v22 v22.3.2 // indirect
7388
github.com/davecgh/go-spew v1.1.1 // indirect
@@ -86,12 +101,12 @@ require (
86101
github.com/jonboulle/clockwork v0.2.2 // indirect
87102
github.com/json-iterator/go v1.1.12 // indirect
88103
github.com/jtolds/gls v4.20.0+incompatible // indirect
89-
github.com/juju/ratelimit v1.0.1 // indirect
104+
github.com/juju/ratelimit v1.0.2-0.20191002062651-f60b32039441 // indirect
90105
github.com/klauspost/compress v1.13.6 // indirect
91106
github.com/klauspost/cpuid/v2 v2.0.3 // indirect
92107
github.com/kr/pretty v0.3.0 // indirect
93108
github.com/kr/text v0.2.0 // indirect
94-
github.com/lni/vfs v0.2.1-0.20210810090357-27c7525cf64f // indirect
109+
github.com/lni/vfs v0.2.1-0.20220408085249-8be85be1c3c1
95110
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
96111
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
97112
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect

go.sum

+95-18
Large diffs are not rendered by default.

pkg/common/moerr/error.go

+7
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@ const (
3434
// Group 2: numeric
3535
DIVIVISION_BY_ZERO = 2000 + iota
3636
OUT_OF_RANGE
37+
38+
// Group 3: invalid input
39+
BAD_CONFIGURATION = 3000 + iota
40+
INVALID_INPUT
41+
42+
// Group 4: unexpected state
43+
INVALID_STATE = 4000 + iota
3744
)
3845

3946
type Error struct {

pkg/hakeeper/rsm.go

+243
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
1+
// Copyright 2021 - 2022 Matrix Origin
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package hakeeper
16+
17+
import (
18+
"encoding/binary"
19+
"encoding/gob"
20+
"io"
21+
"time"
22+
23+
"github.com/lni/dragonboat/v4/logger"
24+
sm "github.com/lni/dragonboat/v4/statemachine"
25+
26+
"github.com/matrixorigin/matrixone/pkg/common/moerr"
27+
"github.com/matrixorigin/matrixone/pkg/pb/logservice"
28+
)
29+
30+
var (
31+
plog = logger.GetLogger("hakeeper")
32+
)
33+
34+
var (
35+
binaryEnc = binary.BigEndian
36+
)
37+
38+
const (
39+
// TickDuration defines the frequency of ticks.
40+
TickDuration = time.Second
41+
// DefaultHAKeeperShardID is the shard ID assigned to the special HAKeeper
42+
// shard.
43+
DefaultHAKeeperShardID uint64 = 0
44+
45+
headerSize = 2
46+
)
47+
48+
const (
49+
createLogShardTag uint16 = iota + 0xAE01
50+
tickTag
51+
dnHeartbeatTag
52+
logHeartbeatTag
53+
)
54+
55+
type logShardIDQuery struct {
56+
name string
57+
}
58+
59+
type logShardIDQueryResult struct {
60+
id uint64
61+
found bool
62+
}
63+
64+
type stateMachine struct {
65+
replicaID uint64
66+
67+
Tick uint64
68+
NextID uint64
69+
70+
LogShards map[string]uint64
71+
DNState DNState
72+
LogState LogState
73+
}
74+
75+
func parseCmdTag(cmd []byte) uint16 {
76+
return binaryEnc.Uint16(cmd)
77+
}
78+
79+
func getCreateLogShardCmd(name string) []byte {
80+
return getLogShardCmd(name, createLogShardTag)
81+
}
82+
83+
func getLogShardCmd(name string, tag uint16) []byte {
84+
cmd := make([]byte, headerSize+len(name))
85+
binaryEnc.PutUint16(cmd, tag)
86+
copy(cmd[headerSize:], []byte(name))
87+
return cmd
88+
}
89+
90+
func isCreateLogShardCmd(cmd []byte) (string, bool) {
91+
return isLogShardCmd(cmd, createLogShardTag)
92+
}
93+
94+
func isDNHeartbeatCmd(cmd []byte) bool {
95+
return isHeartbeatCmd(cmd, dnHeartbeatTag)
96+
}
97+
98+
func isLogHeartbeatCmd(cmd []byte) bool {
99+
return isHeartbeatCmd(cmd, logHeartbeatTag)
100+
}
101+
102+
func isHeartbeatCmd(cmd []byte, tag uint16) bool {
103+
if len(cmd) <= headerSize {
104+
return false
105+
}
106+
return parseCmdTag(cmd) == tag
107+
}
108+
109+
func parseHeartbeatCmd(cmd []byte) []byte {
110+
return cmd[headerSize:]
111+
}
112+
113+
func isLogShardCmd(cmd []byte, tag uint16) (string, bool) {
114+
if len(cmd) <= headerSize {
115+
return "", false
116+
}
117+
if parseCmdTag(cmd) == tag {
118+
return string(cmd[headerSize:]), true
119+
}
120+
return "", false
121+
}
122+
123+
func isTickCmd(cmd []byte) bool {
124+
return len(cmd) == headerSize && binaryEnc.Uint16(cmd) == tickTag
125+
}
126+
127+
func GetTickCmd() []byte {
128+
cmd := make([]byte, headerSize)
129+
binaryEnc.PutUint16(cmd, tickTag)
130+
return cmd
131+
}
132+
133+
func GetLogStoreHeartbeatCmd(data []byte) []byte {
134+
return getHeartbeatCmd(data, logHeartbeatTag)
135+
}
136+
137+
func GetDNStoreHeartbeatCmd(data []byte) []byte {
138+
return getHeartbeatCmd(data, dnHeartbeatTag)
139+
}
140+
141+
func getHeartbeatCmd(data []byte, tag uint16) []byte {
142+
cmd := make([]byte, headerSize+len(data))
143+
binaryEnc.PutUint16(cmd, tag)
144+
copy(cmd[headerSize:], data)
145+
return cmd
146+
}
147+
148+
func NewStateMachine(shardID uint64, replicaID uint64) sm.IStateMachine {
149+
if shardID != DefaultHAKeeperShardID {
150+
panic(moerr.NewError(moerr.INVALID_INPUT, "invalid HAKeeper shard ID"))
151+
}
152+
return &stateMachine{
153+
replicaID: replicaID,
154+
LogShards: make(map[string]uint64),
155+
DNState: NewDNState(),
156+
LogState: NewLogState(),
157+
}
158+
}
159+
160+
func (s *stateMachine) Close() error {
161+
return nil
162+
}
163+
164+
func (s *stateMachine) assignID() uint64 {
165+
s.NextID++
166+
return s.NextID
167+
}
168+
169+
func (s *stateMachine) handleCreateLogShardCmd(cmd []byte) (sm.Result, error) {
170+
name, ok := isCreateLogShardCmd(cmd)
171+
if !ok {
172+
panic(moerr.NewError(moerr.INVALID_INPUT, "not create log shard cmd"))
173+
}
174+
if shardID, ok := s.LogShards[name]; ok {
175+
data := make([]byte, 8)
176+
binaryEnc.PutUint64(data, shardID)
177+
return sm.Result{Value: 0, Data: data}, nil
178+
}
179+
s.LogShards[name] = s.assignID()
180+
return sm.Result{Value: s.NextID}, nil
181+
}
182+
183+
func (s *stateMachine) handleDNHeartbeat(cmd []byte) (sm.Result, error) {
184+
data := parseHeartbeatCmd(cmd)
185+
var hb logservice.DNStoreHeartbeat
186+
if err := hb.Unmarshal(data); err != nil {
187+
panic(err)
188+
}
189+
s.DNState.Update(hb, s.Tick)
190+
return sm.Result{}, nil
191+
}
192+
193+
func (s *stateMachine) handleLogHeartbeat(cmd []byte) (sm.Result, error) {
194+
data := parseHeartbeatCmd(cmd)
195+
var hb logservice.LogStoreHeartbeat
196+
if err := hb.Unmarshal(data); err != nil {
197+
panic(err)
198+
}
199+
s.LogState.Update(hb, s.Tick)
200+
return sm.Result{}, nil
201+
}
202+
203+
func (s *stateMachine) handleTick(cmd []byte) (sm.Result, error) {
204+
s.Tick++
205+
return sm.Result{}, nil
206+
}
207+
208+
func (s *stateMachine) Update(e sm.Entry) (sm.Result, error) {
209+
cmd := e.Cmd
210+
if _, ok := isCreateLogShardCmd(cmd); ok {
211+
return s.handleCreateLogShardCmd(cmd)
212+
} else if isDNHeartbeatCmd(cmd) {
213+
return s.handleDNHeartbeat(cmd)
214+
} else if isLogHeartbeatCmd(cmd) {
215+
return s.handleLogHeartbeat(cmd)
216+
} else if isTickCmd(cmd) {
217+
return s.handleTick(cmd)
218+
}
219+
panic(moerr.NewError(moerr.INVALID_INPUT, "unexpected haKeeper cmd"))
220+
}
221+
222+
func (s *stateMachine) Lookup(query interface{}) (interface{}, error) {
223+
if q, ok := query.(*logShardIDQuery); ok {
224+
id, ok := s.LogShards[q.name]
225+
if ok {
226+
return &logShardIDQueryResult{found: true, id: id}, nil
227+
}
228+
return &logShardIDQueryResult{found: false}, nil
229+
}
230+
panic("unknown query type")
231+
}
232+
233+
func (s *stateMachine) SaveSnapshot(w io.Writer,
234+
_ sm.ISnapshotFileCollection, _ <-chan struct{}) error {
235+
enc := gob.NewEncoder(w)
236+
return enc.Encode(s)
237+
}
238+
239+
func (s *stateMachine) RecoverFromSnapshot(r io.Reader,
240+
_ []sm.SnapshotFile, _ <-chan struct{}) error {
241+
dec := gob.NewDecoder(r)
242+
return dec.Decode(s)
243+
}

0 commit comments

Comments
 (0)