Get(key): 获取键的值,若键不存在返回空字符串。由于 Get 是只读操作,重复执行不会影响状态,无需特别处理序列号。
实现
核心数据结构设计
键值对存储
键值对存储核心的数据结构选择 map,并配合互斥锁(sync.Mutex)保证并发安全
1 2 3 4 5 6
type KVServer struct { mu sync.Mutex store map[string]string clientSeqs map[int64]int// to track the latest sequence number for each client }
store: 存储键值对
clientSeqs:记录每个客户端已经处理过的序列号,用于检测重复请求。
操作原子性
通过互斥锁保护共享资源的访问:
1 2 3 4 5 6 7 8
// Get fetches the current value for the key. // A Get for a non-existing key should return an empty string. func(kv *KVServer) Get(args *GetArgs, reply *GetReply) { kv.mu.Lock() defer kv.mu.Unlock() // 处理 Get 逻辑 }
if args.SeqNumber <= kv.clientSeqs[args.ClientId] { // Repeat the request and return the historical value reply.PreviousValue = kv.store[args.Key] return }
......
// update the request sequence number for the client kv.clientSeqs[args.ClientId] = args.SeqNumber
// send the Get RPC request ok := ck.server.Call("KVServer.Get", &args, &reply) if ok { return reply.Value } return"" }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
// server.go
// Get fetches the current value for the key. // A Get for a non-existing key should return an empty string. func(kv *KVServer) Get(args *GetArgs, reply *GetReply) { kv.mu.Lock() defer kv.mu.Unlock()
value, exists := kv.store[args.Key] if !exists { reply.Value = "" } else { reply.Value = value } }
// Append value to key's value and return that value func(ck *Clerk) Append(key string, value string) string { return ck.PutAppend(key, value, "Append") }
// Put installs or replaces the value for a particular key in the map. func(kv *KVServer) Put(args *PutAppendArgs, reply *PutAppendReply) { kv.mu.Lock() defer kv.mu.Unlock()
if args.SeqNumber <= kv.clientSeqs[args.ClientId] { // Repeat the request and return the historical value reply.PreviousValue = kv.store[args.Key] return }
// update the request sequence number for the client kv.clientSeqs[args.ClientId] = args.SeqNumber }
// Append appends arg to key's value and returns the old value. // An Append to a non-existing key should act as if the existing value were a zero-length string. func(kv *KVServer) Append(args *PutAppendArgs, reply *PutAppendReply) { kv.mu.Lock() defer kv.mu.Unlock()
if args.SeqNumber <= kv.clientSeqs[args.ClientId] { reply.PreviousValue = kv.store[args.Key] return }
// find the key if exist value, exists := kv.store[args.Key] if !exists { // a zero-length string value = "" } // append the value kv.store[args.Key] = value + args.Value reply.PreviousValue = value
// update the request sequence number for the client kv.clientSeqs[args.ClientId] = args.SeqNumber }