Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
176 changes: 1 addition & 175 deletions .claude/settings.local.json
Original file line number Diff line number Diff line change
@@ -1,181 +1,7 @@
{
"permissions": {
"allow": [
"Bash(find:*)",
"Bash(CGO_LDFLAGS=\"-Wl,-U,_SecTrustCopyCertificateChain\" go build:*)",
"Bash(tree:*)",
"Bash(grep -E \"(Starting|became leader|elected leader)\" echo \"\" echo \"=== 节点2 ===\" tail -5 /tmp/node2.log)",
"Bash(grep -E \"(Starting|became leader|became follower|elected leader)\" echo \"\" echo \"=== 节点3 ===\" tail -5 /tmp/node3.log)",
"Bash(mkdir:*)",
"Bash(mv:*)",
"Bash(go version:*)",
"Bash(go mod tidy:*)",
"Bash(go mod download:*)",
"Bash(cat:*)",
"Bash(make help:*)",
"Bash(make clean:*)",
"Bash(make build:*)",
"Bash(make cluster-memory:*)",
"Bash(make status:*)",
"Bash(make stop-cluster:*)",
"Bash(CGO_ENABLED=1 CGO_LDFLAGS=\"-lrocksdb -lpthread -lstdc++ -ldl -lm -lzstd -llz4 -lz -lsnappy -lbz2\" go build:*)",
"Bash(./metaStore --help)",
"Bash(go test:*)",
"Bash(CGO_ENABLED=1 CGO_LDFLAGS=\"-lrocksdb -lpthread -lstdc++ -ldl -lm -lzstd -llz4 -lz -lsnappy -lbz2\" go test:*)",
"Bash(make test:*)",
"Bash(git add:*)",
"Bash(git commit -m \"$(cat <<''EOF''\nrefactor: migrate to golang-standards/project-layout structure\n\nThis is a major refactoring that reorganizes the codebase from a flat\nstructure in the root directory to a standard Go project layout following\ngolang-standards/project-layout conventions.\n\nKey changes:\n- Move application entry point to cmd/metastore/main.go\n- Reorganize core code into internal/ packages by functional layer:\n - internal/store: Storage interface and implementations (memory/rocksdb)\n - internal/raft: Raft consensus layer (node implementations)\n - internal/http: HTTP API layer\n - internal/storage: Low-level storage engine (RocksDB wrapper)\n - internal/kvstore: KV store interface definitions\n - internal/memory: Memory-based KV store implementation\n - internal/rocksdb: RocksDB-based implementations\n- Remove flat structure files from root directory\n- Update Makefile to use new cmd/metastore path\n- Add PROJECT_LAYOUT.md documenting the new structure\n- Add comprehensive testing documentation in docs/TESTING.md\n- Migrate all tests to corresponding internal packages\n\nBenefits:\n- Better code organization with clear functional separation\n- Follows Go community best practices\n- Better encapsulation using internal packages\n- Improved modularity with interface-based interactions\n- Easier to test with clear package boundaries\n- Enhanced project professionalism and maintainability\n\nAll functionality and APIs remain unchanged - this is purely a structural\nrefactoring with no behavioral changes.\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\nCo-Authored-By: Claude <noreply@anthropic.com>\nEOF\n)\")",
"Bash(git commit:*)",
"Bash(git restore:*)",
"Bash(export CGO_ENABLED=1:*)",
"Bash(export CGO_LDFLAGS=\"-lrocksdb -lpthread -lstdc++ -ldl -lm -lzstd -llz4 -lz -lsnappy -lbz2\":*)",
"Bash(timeout 60 go test:*)",
"Bash(timeout 120 go test:*)",
"Bash(timeout 30 go test:*)",
"Bash(git rm:*)",
"Bash(go get:*)",
"Bash(go build:*)",
"Bash(CGO_ENABLED=0 go build:*)",
"Bash(pkill:*)",
"Bash(CGO_ENABLED=0 go test:*)",
"Bash(CGO_ENABLED=1 CGO_LDFLAGS=\"-lrocksdb -lpthread -lstdc++ -ldl -lm -lzstd -llz4 -lz -lsnappy -lbz2 -Wl,-U,_SecTrustCopyCertificateChain\" go test:*)",
"Bash(timeout 120 bash:*)",
"Bash(/dev/null)",
"Bash(go clean:*)",
"Bash(CGO_ENABLED=1 CGO_LDFLAGS=\"-lrocksdb -lpthread -lstdc++ -ldl -lm -lzstd -llz4 -lz -lsnappy -lbz2 -Wl,-U,_SecTrustCopyCertificateChain\" go test ./test -run \"TestEtcdRocksDBSingleNodeOperations/PutAndGet\" -v -timeout=30s)",
"Bash(CGO_ENABLED=1 CGO_LDFLAGS=\"-lrocksdb -lpthread -lstdc++ -ldl -lm -lzstd -llz4 -lz -lsnappy -lbz2 -Wl,-U,_SecTrustCopyCertificateChain\" go run:*)",
"Bash(go doc:*)",
"Bash(CGO_ENABLED=1 CGO_LDFLAGS=\"-lrocksdb -lpthread -lstdc++ -ldl -lm -lzstd -llz4 -lz -lsnappy -lbz2 -Wl,-U,_SecTrustCopyCertificateChain\" go build:*)",
"Bash(tee:*)",
"Read(//Users/bast/go/pkg/mod/go.etcd.io/etcd/client/v3@v3.6.4/**)",
"Read(//Users/bast/go/pkg/mod/go.etcd.io/etcd/**)",
"Read(//private/tmp/**)",
"Bash(make test-unit:*)",
"Bash(for file in /Users/bast/code/MetaStore/PROJECT_LAYOUT.md )",
"Bash(/Users/bast/code/MetaStore/docs/PROJECT_SUMMARY.md )",
"Bash(/Users/bast/code/MetaStore/docs/ROCKSDB_3NODE_TEST_REPORT.md )",
"Bash(/Users/bast/code/MetaStore/docs/phase2-design.md )",
"Bash(/Users/bast/code/MetaStore/docs/DIRECTORY_STRUCTURE_CHANGE_REPORT.md )",
"Bash(/Users/bast/code/MetaStore/docs/ROCKSDB_BUILD_MACOS.md )",
"Bash(/Users/bast/code/MetaStore/docs/ROCKSDB_TEST_GUIDE.md )",
"Bash(/Users/bast/code/MetaStore/docs/PHASE2_COMPLETION_REPORT.md )",
"Bash(/Users/bast/code/MetaStore/docs/ROCKSDB_BUILD_MACOS_EN.md )",
"Bash(/Users/bast/code/MetaStore/docs/ROCKSDB_TEST_REPORT.md )",
"Bash(/Users/bast/code/MetaStore/docs/TEST_COVERAGE_REPORT.md )",
"Bash(/Users/bast/code/MetaStore/test_phase2.sh )",
"Bash(/Users/bast/code/MetaStore/test_phase2_cluster.sh:*)",
"Bash(do:*)",
"Bash(done)",
"Bash(./metastore:*)",
"Bash(git checkout:*)",
"Bash(for:*)",
"Bash(/Users/bast/code/MetaStore/test/etcd_memory_integration_test.go )",
"Bash(/Users/bast/code/MetaStore/test/cross_protocol_integration_test.go )",
"Bash(/Users/bast/code/MetaStore/test/http_api_memory_integration_test.go )",
"Bash(/Users/bast/code/MetaStore/test/http_api_memory_consistency_test.go )",
"Bash(/Users/bast/code/MetaStore/internal/memory/kvstore_etcd_raft.go)",
"Bash(/Users/bast/code/MetaStore/test/etcd_compatibility_test.go )",
"Bash(/Users/bast/code/MetaStore/test/etcd_rocksdb_integration_test.go )",
"Bash(/Users/bast/code/MetaStore/test/http_api_rocksdb_consistency_test.go )",
"Bash(/Users/bast/code/MetaStore/internal/rocksdb/kvstore_etcd_raft.go)",
"Bash(git mv:*)",
"Bash(awk:*)",
"Bash(/Users/bast/code/MetaStore/pkg/etcdapi/server.go )",
"Bash(/Users/bast/code/MetaStore/pkg/etcdapi/kv.go )",
"Bash(/Users/bast/code/MetaStore/pkg/etcdapi/lease_manager.go )",
"Bash(/Users/bast/code/MetaStore/pkg/etcdapi/maintenance.go )",
"Bash(/Users/bast/code/MetaStore/pkg/etcdapi/watch_manager.go )",
"Bash(/Users/bast/code/MetaStore/pkg/etcdapi/lease.go )",
"Bash(/Users/bast/code/MetaStore/pkg/etcdapi/watch.go )",
"Bash(/Users/bast/code/MetaStore/pkg/etcdapi/errors.go)",
"Bash(GOPROXY=https://proxy.golang.org,direct go mod tidy:*)",
"Bash(pkg/etcdapi/kv.go)",
"Bash([ -f \"$file\" ])",
"Bash(\"$file\")",
"Bash(pkg/etcdapi/lease_manager.go)",
"Bash(sed:*)",
"Bash(internal/rocksdb/kvstore.go)",
"Bash(internal/memory/store.go)",
"Bash(internal/memory/watch.go)",
"Bash(chmod:*)",
"Bash(xargs kill:*)",
"Bash(lsof:*)",
"Bash(make test-maintenance:*)",
"Bash(timeout 600 make test:*)",
"Bash(while ps aux)",
"Bash(sample:*)",
"Bash(if ! ps aux)",
"Bash(then echo \"测试已完成!\")",
"Bash(exit 0)",
"Bash(fi)",
"Bash(kill:*)",
"Bash(echo:*)",
"Bash(ps:*)",
"Bash(while ps:*)",
"Bash(while true)",
"Bash(if ps -p 58114)",
"Bash(then)",
"Bash(else)",
"Bash(break)",
"Bash(xargs:*)",
"Bash(while read f)",
"Bash(sort:*)",
"Bash(./test_cluster.sh:*)",
"Bash(CGO_ENABLED=1 CGO_LDFLAGS=\"-lrocksdb -lpthread -lstdc++ -ldl -lm -lzstd -llz4 -lz -lsnappy -lbz2 -Wl,-U,_SecTrustCopyCertificateChain\" timeout 60 go test:*)",
"Bash(CGO_ENABLED=1 CGO_LDFLAGS=\"-lrocksdb -lpthread -lstdc++ -ldl -lm -lzstd -llz4 -lz -lsnappy -lbz2 -Wl,-U,_SecTrustCopyCertificateChain\" timeout 120 go test:*)",
"Bash(go install:*)",
"Bash(brew install:*)",
"Bash(protoc:*)",
"Bash(export PATH=$PATH:$HOME/go/bin)",
"Bash(CGO_ENABLED=1 CGO_LDFLAGS=\"-lrocksdb -lpthread -lstdc++ -ldl -lm -lzstd -llz4 -lz -lsnappy -lbz2 -Wl,-U,_SecTrustCopyCertificateChain\" timeout 600 go test:*)",
"Bash(CGO_ENABLED=1 CGO_LDFLAGS=\"-lrocksdb -lpthread -lstdc++ -ldl -lm -lzstd -llz4 -lz -lsnappy -lbz2 -Wl,-U,_SecTrustCopyCertificateChain\" timeout 180 go test:*)",
"Bash(CGO_ENABLED=1 CGO_LDFLAGS=\"-lrocksdb -lpthread -lstdc++ -ldl -lm -lzstd -llz4 -lz -lsnappy -lbz2 -Wl,-U,_SecTrustCopyCeptificateChain\" go test:*)",
"Bash(make test-perf-memory:*)",
"Bash(make test-perf-rocksdb:*)",
"Bash(protoc-gen-go:*)",
"Bash(timeout 5 ./metastore:*)",
"Bash(timeout:*)",
"Bash(CGO_ENABLED=1 CGO_LDFLAGS=\"-lrocksdb -lpthread -lstdc++ -ldl -lm -lzstd -llz4 -lz -lsnappy -lbz2 -Wl,-U,_SecTrustCopyCertificateChain\" go list:*)",
"Bash(CGO_ENABLED=1 CGO_LDFLAGS=\"-lrocksdb -lpthread -lstdc++ -ldl -lm -lzstd -llz4 -lz -lsnappy -lbz2 -Wl,-U,_SecTrustCopyCertificateChain\" timeout 300 go test:*)",
"Bash(CGO_ENABLED=1 CGO_LDFLAGS=\"-lrocksdb -lpthread -lstdc++ -ldl -lm -lzstd -llz4 -lz -lsnappy -lbz2 -Wl,-U,_SecTrustCopyCertificateChain\" timeout 90 go test:*)",
"Bash(GOEXPERIMENT=greenteagc CGO_ENABLED=0 go build:*)",
"Bash(GOEXPERIMENT=greenteagc CGO_ENABLED=1 CGO_LDFLAGS=\"-lrocksdb -lpthread -lstdc++ -ldl -lm -lzstd -llz4 -lz -lsnappy -lbz2 -Wl,-U,_SecTrustCopyCertificateChain\" go build:*)",
"Bash(GOEXPERIMENT=greenteagc CGO_ENABLED=0 go test:*)",
"Bash(GOEXPERIMENT=greenteagc CGO_ENABLED=1 CGO_LDFLAGS=\"-lrocksdb -lpthread -lstdc++ -ldl -lm -lzstd -llz4 -lz -lsnappy -lbz2 -Wl,-U,_SecTrustCopyCertificateChain\" go test:*)",
"Bash(bash -n:*)",
"Bash(./test_mysql_single.sh:*)",
"Bash(mysql:*)",
"Bash(./test_mysql_quick.sh:*)",
"Bash(bash test_mysql_cluster.sh:*)",
"Bash(bash test_mysql_cluster_simple.sh:*)",
"Bash(bash:*)",
"Bash(export CGO_LDFLAGS=\"-lrocksdb -lpthread -lstdc++ -ldl -lm -lzstd -llz4 -lz -lsnappy -lbz2 -Wl,-U,_SecTrustCopyCertificateChain\":*)",
"Bash(go run:*)",
"Bash(brew search:*)",
"Bash(done echo 'Installation completed' ls -la /usr/local/opt/)",
"Bash(/usr/local/Cellar/mysql-client@8.0/*/bin/mysql)",
"Bash(/usr/local/Cellar/mysql-client@8.0/8.0.44/bin/mysql:*)",
"Bash(curl:*)",
"Bash(tools/etcdctl:*)",
"Bash(unset http_proxy unset https_proxy curl -X PUT http://127.0.0.1:9991/testkey3 -d \"testvalue3\")",
"Bash(env -u http_proxy -u https_proxy curl -X PUT http://127.0.0.1:9991/testkey3 -d \"testvalue3\")",
"Bash(env -u http_proxy -u https_proxy curl http://127.0.0.1:9991/testkey3)",
"Bash(env -u http_proxy -u https_proxy curl -v -X PUT http://127.0.0.1:9991/testkey -d \"testvalue\")",
"Bash(env -u http_proxy -u https_proxy -u all_proxy curl -v -X PUT http://127.0.0.1:9991/testkey -d \"testvalue\")",
"Bash(env -u http_proxy -u https_proxy -u all_proxy curl -v http://127.0.0.1:9991/testkey)",
"Bash(./test_tidb_parser.sh:*)",
"Bash(./test_sql_parser.sh:*)",
"Bash(then echo \"✓ 新格式 (包含 etcd/http/mysql 配置)\" elif grep -q \"mysql:\" \"$f\")",
"Bash(then if grep -q \"enable:\" \"$f\")",
"Bash(then echo \"✗ 旧格式 (包含 enable 字段)\" else echo \"? 部分更新\" fi else echo \"- 无 MySQL 配置\" fi done)",
"Bash(grep:*)",
"Bash(GOEXPERIMENT=greenteagc CGO_ENABLED=1 'CGO_LDFLAGS=-lrocksdb -lpthread -lstdc++ -ldl -lm -lzstd -llz4 -lz -lsnappy -lbz2 -Wl,-U,_SecTrustCopyCertificateChain' go test -p 1 -run ^Test[^B] ./test/...)",
"Bash(GOEXPERIMENT=greenteagc CGO_ENABLED=1 'CGO_LDFLAGS=-lrocksdb -lpthread -lstdc++ -ldl -lm -lzstd -llz4 -lz -lsnappy -lbz2 -Wl,-U,_SecTrustCopyCertificateChain' go test -v -p 1 ./test/... -run TestEtcdMemorySingleNode -timeout=120s)",
"Bash(GOEXPERIMENT=greenteagc CGO_ENABLED=1 'CGO_LDFLAGS=-lrocksdb -lpthread -lstdc++ -ldl -lm -lzstd -llz4 -lz -lsnappy -lbz2 -Wl,-U,_SecTrustCopyCertificateChain' go test -p 1 ./internal/... ./pkg/... ./api/...)",
"Bash(GOEXPERIMENT=greenteagc CGO_ENABLED=1 'CGO_LDFLAGS=-lrocksdb -lpthread -lstdc++ -ldl -lm -lzstd -llz4 -lz -lsnappy -lbz2 -Wl,-U,_SecTrustCopyCertificateChain' go test -v ./test/... -run TestCrossProtocolMemoryDataInteroperability -timeout=120s)",
"Bash(GOEXPERIMENT=greenteagc CGO_ENABLED=1 'CGO_LDFLAGS=-lrocksdb -lpthread -lstdc++ -ldl -lm -lzstd -llz4 -lz -lsnappy -lbz2 -Wl,-U,_SecTrustCopyCertificateChain' go test -v ./test/... -run TestEtcdMemoryClusterBasicConsistency -timeout=120s)",
"Bash(GOEXPERIMENT=greenteagc CGO_ENABLED=1 'CGO_LDFLAGS=-lrocksdb -lpthread -lstdc++ -ldl -lm -lzstd -llz4 -lz -lsnappy -lbz2 -Wl,-U,_SecTrustCopyCertificateChain' go test -v ./test/... -run TestEtcdRocksDBSingleNodeOperations -timeout=120s)",
"Bash(make:*)"

],
"deny": [],
"ask": []
Expand Down
41 changes: 38 additions & 3 deletions api/etcd/kv.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,46 @@ type KVServer struct {
func (s *KVServer) Range(ctx context.Context, req *pb.RangeRequest) (*pb.RangeResponse, error) {
key := string(req.Key)
rangeEnd := string(req.RangeEnd)
limit := req.Limit
revision := req.Revision

// 构建 RangeOptions
opts := kvstore.RangeOptions{
Limit: req.Limit,
Revision: req.Revision,
MaxCreateRevision: req.MaxCreateRevision,
MinCreateRevision: req.MinCreateRevision,
MaxModRevision: req.MaxModRevision,
MinModRevision: req.MinModRevision,
CountOnly: req.CountOnly,
KeysOnly: req.KeysOnly,
}

// 转换排序选项
switch req.SortOrder {
case pb.RangeRequest_ASCEND:
opts.SortOrder = kvstore.SortAscend
case pb.RangeRequest_DESCEND:
opts.SortOrder = kvstore.SortDescend
default:
opts.SortOrder = kvstore.SortNone
}

switch req.SortTarget {
case pb.RangeRequest_KEY:
opts.SortTarget = kvstore.SortByKey
case pb.RangeRequest_VERSION:
opts.SortTarget = kvstore.SortByVersion
case pb.RangeRequest_CREATE:
opts.SortTarget = kvstore.SortByCreate
case pb.RangeRequest_MOD:
opts.SortTarget = kvstore.SortByMod
case pb.RangeRequest_VALUE:
opts.SortTarget = kvstore.SortByValue
default:
opts.SortTarget = kvstore.SortByKey
}

// 从 store 查询
resp, err := s.server.store.Range(ctx, key, rangeEnd, limit, revision)
resp, err := s.server.store.RangeWithOptions(ctx, key, rangeEnd, opts)
if err != nil {
return nil, toGRPCError(err)
}
Expand Down
21 changes: 16 additions & 5 deletions api/etcd/lease.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package etcd

import (
"context"
"errors"

pb "go.etcd.io/etcd/api/v3/etcdserverpb"
)
Expand All @@ -31,9 +32,9 @@ func (s *LeaseServer) LeaseGrant(ctx context.Context, req *pb.LeaseGrantRequest)
ttl := req.TTL
id := req.ID

// 如果没有指定 ID,自动生成
// 如果没有指定 ID,自动生成唯一 ID
if id == 0 {
id = s.server.store.CurrentRevision() + 1
id = s.server.leaseMgr.GenerateLeaseID()
}

// 创建 lease
Expand Down Expand Up @@ -98,13 +99,23 @@ func (s *LeaseServer) LeaseTimeToLive(ctx context.Context, req *pb.LeaseTimeToLi
// 获取 lease 信息
lease, err := s.server.leaseMgr.TimeToLive(id)
if err != nil {
// 对于不存在的 Lease,etcd 返回 TTL=-1 而不是错误
// 这符合 etcd 客户端的期望行为
if errors.Is(err, ErrLeaseNotFound) {
return &pb.LeaseTimeToLiveResponse{
Header: s.server.getResponseHeader(),
ID: id,
TTL: -1,
GrantedTTL: 0,
}, nil
}
return nil, toGRPCError(err)
}

resp := &pb.LeaseTimeToLiveResponse{
Header: s.server.getResponseHeader(),
ID: lease.ID,
TTL: lease.Remaining(),
Header: s.server.getResponseHeader(),
ID: lease.ID,
TTL: lease.Remaining(),
GrantedTTL: lease.TTL,
}

Expand Down
21 changes: 21 additions & 0 deletions api/etcd/lease_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,21 @@ type LeaseManager struct {
checkInterval time.Duration // Lease 过期检查间隔
defaultTTL time.Duration // 默认 TTL
maxLeaseCount int // 最大 Lease 数量限制(0 表示无限制)

// Lease ID 生成器 (集群安全)
// ID 格式: 高16位为节点ID,低48位为计数器
nodeID uint64
leaseIDCounter atomic.Int64
}

// NewLeaseManager 创建新的 Lease 管理器
// 参数: store, leaseConfig (可选), limitsConfig (可选)
func NewLeaseManager(store kvstore.Store, leaseCfg *config.LeaseConfig, limitsCfg *config.LimitsConfig) *LeaseManager {
return NewLeaseManagerWithNodeID(store, leaseCfg, limitsCfg, 1)
}

// NewLeaseManagerWithNodeID 创建新的 Lease 管理器(带节点 ID,用于集群)
func NewLeaseManagerWithNodeID(store kvstore.Store, leaseCfg *config.LeaseConfig, limitsCfg *config.LimitsConfig, nodeID uint64) *LeaseManager {
// 使用配置或默认值
if leaseCfg == nil {
defaultCfg := config.DefaultConfig(1, 1, ":2379")
Expand All @@ -61,6 +71,7 @@ func NewLeaseManager(store kvstore.Store, leaseCfg *config.LeaseConfig, limitsCf
checkInterval: leaseCfg.CheckInterval,
defaultTTL: leaseCfg.DefaultTTL,
maxLeaseCount: maxLeases,
nodeID: nodeID,
}
}

Expand All @@ -77,6 +88,16 @@ func (lm *LeaseManager) Stop() {
close(lm.stopCh)
}

// GenerateLeaseID 生成集群唯一的 Lease ID
// ID 格式: 高16位为节点ID,低48位为计数器
// 这样每个节点可以独立生成不冲突的 ID
func (lm *LeaseManager) GenerateLeaseID() int64 {
counter := lm.leaseIDCounter.Add(1)
// 高16位: nodeID, 低48位: counter
// 支持最多 65535 个节点,每个节点 2^48 个 Lease
return int64(lm.nodeID<<48) | (counter & 0x0000FFFFFFFFFFFF)
}

// Grant 创建一个新的 lease
func (lm *LeaseManager) Grant(id int64, ttl int64) (*kvstore.Lease, error) {
if lm.stopped.Load() {
Expand Down
6 changes: 5 additions & 1 deletion internal/kvstore/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,18 @@ type Store interface {

// etcd-compatible methods with Context support

// Range executes a range query
// Range executes a range query (legacy, for backward compatibility)
// ctx: context for timeout and cancellation
// key: start key
// rangeEnd: end key (empty for single key, "\x00" for all keys)
// limit: max keys to return (0 for unlimited)
// revision: query data at specific revision (0 for latest)
Range(ctx context.Context, key, rangeEnd string, limit int64, revision int64) (*RangeResponse, error)

// RangeWithOptions executes a range query with full options support
// This is the preferred method for complex queries (sorting, filtering by revision, etc.)
RangeWithOptions(ctx context.Context, key, rangeEnd string, opts RangeOptions) (*RangeResponse, error)

// PutWithLease stores a key-value pair with optional lease
// Returns new revision and previous value (if any)
PutWithLease(ctx context.Context, key, value string, leaseID int64) (revision int64, prevKv *KeyValue, err error)
Expand Down
34 changes: 34 additions & 0 deletions internal/kvstore/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,40 @@ type OpResponse struct {
DeleteResp *DeleteResponse
}

// RangeOptions Range 操作选项
type RangeOptions struct {
Limit int64 // 返回键数量限制
Revision int64 // 查询指定 revision 的数据
SortOrder SortOrder // 排序顺序
SortTarget SortTarget // 排序目标
MaxCreateRevision int64 // 最大创建 revision 过滤
MinCreateRevision int64 // 最小创建 revision 过滤
MaxModRevision int64 // 最大修改 revision 过滤
MinModRevision int64 // 最小修改 revision 过滤
CountOnly bool // 只返回数量
KeysOnly bool // 只返回键
}

// SortOrder 排序顺序
type SortOrder int

const (
SortNone SortOrder = 0
SortAscend SortOrder = 1
SortDescend SortOrder = 2
)

// SortTarget 排序目标
type SortTarget int

const (
SortByKey SortTarget = 0
SortByVersion SortTarget = 1
SortByCreate SortTarget = 2
SortByMod SortTarget = 3
SortByValue SortTarget = 4
)

// RangeResponse Range 操作响应
type RangeResponse struct {
Kvs []*KeyValue
Expand Down
Loading