Featured image of post Mit lab2个人笔记

Mit lab2个人笔记

Mit 6.824 lab2个人笔记

源码地址:https://github.com/liusir521/mit6.5840

简介

实验二要求我们实现一个单机版的键值服务器,并实现Get\Put\Append方法。需要考虑的重点是多个客户端并发访问的问题以及由于网络原因导致的客户端请求重试问题(幂等性)。

实验二其实并不难,针对Get操作我们不需要做过多的处理,主要是Put和Append操作。我们只需要在服务端定义好存储客户端id与该客户端请求id的对应关系,以及客户端id和上次缓存的结果即可(用于Append请求)。

代码实现

客户端

客户端的代码主要在client.go文件中,该文件中需要我们完善Clerk客户端结构体,其中我们需要添加clientID以及requestID即可,文件中已经提供了相关的函数,我们只需要在每次Put请求和Append请求成功时增加requestID即可。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66

type Clerk struct {
	server *labrpc.ClientEnd
	clientID  int64
	requestID int64
	mu        sync.Mutex
}

func nrand() int64 {
	max := big.NewInt(int64(1) << 62)
	bigx, _ := rand.Int(rand.Reader, max)
	x := bigx.Int64()
	return x
}

func MakeClerk(server *labrpc.ClientEnd) *Clerk {
	ck := &Clerk{
		clientID:  nrand(),
		requestID: 0,
	}
	ck.server = server
	return ck
}

func (ck *Clerk) Get(key string) string {

	args := GetArgs{Key: key}
	var reply GetReply
	for {
		ok := ck.server.Call("KVServer.Get", &args, &reply)
		if ok {
			return reply.Value
		} else {
			time.Sleep(100 * time.Millisecond)
		}
	}
}

func (ck *Clerk) PutAppend(key string, value string, op string) string {
	args := PutAppendArgs{
		ClientId:  ck.clientID,
		Key:       key,
		Value:     value,
		RequestId: ck.requestID,
	}
	var reply PutAppendReply
	for {
		ok := ck.server.Call("KVServer."+op, &args, &reply)
		if ok {
			ck.mu.Lock()
			ck.requestID++
			ck.mu.Unlock()
			return reply.Value
		} else {
			time.Sleep(100 * time.Millisecond)
		}
	}
}

func (ck *Clerk) Put(key string, value string) {
	ck.PutAppend(key, value, "Put")
}

func (ck *Clerk) Append(key string, value string) string {
	return ck.PutAppend(key, value, "Append")
}

rpc定义

关于rpc的定义位于common.go文件中,代码如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Put or Append
type PutAppendArgs struct {
	Key   string
	Value string
	// You'll have to add definitions here.
	// Field names must start with capital letters,
	// otherwise RPC will break.
	ClientId  int64
	RequestId int64
}

type PutAppendReply struct {
	Value string
}

type GetArgs struct {
	Key string
	// You'll have to add definitions here.
}

type GetReply struct {
	Value string
}

服务端

服务端需要我们修改KVServer结构体来满足Append请求,具体代码如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56

type KVServer struct {
	mu sync.Mutex

	// Your definitions here.
	data                map[string]string
	lastclientrequestid map[int64]int64
	lastclientresponse  map[int64]string // 记录每个客户端上次请求的返回值,只用于Append方法
}

func (kv *KVServer) Get(args *GetArgs, reply *GetReply) {
	// Your code here.
	kv.mu.Lock()
	defer kv.mu.Unlock()
	reply.Value = kv.data[args.Key]
}

func (kv *KVServer) Put(args *PutAppendArgs, reply *PutAppendReply) {
	// Your code here.
	kv.mu.Lock()
	defer kv.mu.Unlock()
	lastReqId, exists := kv.lastclientrequestid[args.ClientId]
	if !exists || args.RequestId > lastReqId {
		kv.lastclientrequestid[args.ClientId] = args.RequestId
		kv.data[args.Key] = args.Value
	}
}

func (kv *KVServer) Append(args *PutAppendArgs, reply *PutAppendReply) {
	// Your code here.
	kv.mu.Lock()
	defer kv.mu.Unlock()
	lastReqId, exists := kv.lastclientrequestid[args.ClientId]
	if !exists || args.RequestId > lastReqId {
		// 新请求,执行追加
		oldvalue := kv.data[args.Key]
		kv.lastclientrequestid[args.ClientId] = args.RequestId
		kv.data[args.Key] += args.Value
		reply.Value = oldvalue
		// 更新记录值
		kv.lastclientresponse[args.ClientId] = oldvalue
	} else {
		// 重复请求,返回上次记录的响应值
		reply.Value = kv.lastclientresponse[args.ClientId]
	}
}

func StartKVServer() *KVServer {
	kv := &KVServer{
		data:                make(map[string]string),
		lastclientrequestid: make(map[int64]int64),
		lastclientresponse:  make(map[int64]string),
	}

	return kv
}

测试结果

结果如下

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计