Delete shardkv1/kvsrv1
This commit is contained in:
parent
5f41773a69
commit
efc69b96f9
@ -1,56 +0,0 @@
|
|||||||
package kvsrv
|
|
||||||
|
|
||||||
import (
|
|
||||||
"6.5840/kvsrv1/rpc"
|
|
||||||
"6.5840/kvtest1"
|
|
||||||
"6.5840/tester1"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
type Clerk struct {
|
|
||||||
clnt *tester.Clnt
|
|
||||||
server string
|
|
||||||
}
|
|
||||||
|
|
||||||
func MakeClerk(clnt *tester.Clnt, server string) kvtest.IKVClerk {
|
|
||||||
ck := &Clerk{clnt: clnt, server: server}
|
|
||||||
// You may add code here.
|
|
||||||
return ck
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get fetches the current value and version for a key. It returns
|
|
||||||
// ErrNoKey if the key does not exist. It keeps trying forever in the
|
|
||||||
// face of all other errors.
|
|
||||||
//
|
|
||||||
// You can send an RPC with code like this:
|
|
||||||
// ok := ck.clnt.Call(ck.server, "KVServer.Get", &args, &reply)
|
|
||||||
//
|
|
||||||
// The types of args and reply (including whether they are pointers)
|
|
||||||
// must match the declared types of the RPC handler function's
|
|
||||||
// arguments. Additionally, reply must be passed as a pointer.
|
|
||||||
func (ck *Clerk) Get(key string) (string, rpc.Tversion, rpc.Err) {
|
|
||||||
// You will have to modify this function.
|
|
||||||
return "", 0, rpc.ErrNoKey
|
|
||||||
}
|
|
||||||
|
|
||||||
// Put updates key with value only if the version in the
|
|
||||||
// request matches the version of the key at the server. If the
|
|
||||||
// versions numbers don't match, the server should return
|
|
||||||
// ErrVersion. If Put receives an ErrVersion on its first RPC, Put
|
|
||||||
// should return ErrVersion, since the Put was definitely not
|
|
||||||
// performed at the server. If the server returns ErrVersion on a
|
|
||||||
// resend RPC, then Put must return ErrMaybe to the application, since
|
|
||||||
// its earlier RPC might have been processed by the server successfully
|
|
||||||
// but the response was lost, and the the Clerk doesn't know if
|
|
||||||
// the Put was performed or not.
|
|
||||||
//
|
|
||||||
// You can send an RPC with code like this:
|
|
||||||
// ok := ck.clnt.Call(ck.server, "KVServer.Put", &args, &reply)
|
|
||||||
//
|
|
||||||
// The types of args and reply (including whether they are pointers)
|
|
||||||
// must match the declared types of the RPC handler function's
|
|
||||||
// arguments. Additionally, reply must be passed as a pointer.
|
|
||||||
func (ck *Clerk) Put(key, value string, version rpc.Tversion) rpc.Err {
|
|
||||||
// You will have to modify this function.
|
|
||||||
return rpc.ErrNoKey
|
|
||||||
}
|
|
@ -1,162 +0,0 @@
|
|||||||
package kvsrv
|
|
||||||
|
|
||||||
import (
|
|
||||||
// "log"
|
|
||||||
"runtime"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"6.5840/kvsrv1/rpc"
|
|
||||||
"6.5840/kvtest1"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Test Put with a single client and a reliable network
|
|
||||||
func TestReliablePut(t *testing.T) {
|
|
||||||
const Val = "6.5840"
|
|
||||||
const Ver = 0
|
|
||||||
|
|
||||||
ts := MakeTestKV(t, true)
|
|
||||||
defer ts.Cleanup()
|
|
||||||
|
|
||||||
ts.Begin("One client and reliable Put")
|
|
||||||
|
|
||||||
ck := ts.MakeClerk()
|
|
||||||
if err := ck.Put("k", Val, Ver); err != rpc.OK {
|
|
||||||
t.Fatalf("Put err %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if val, ver, err := ck.Get("k"); err != rpc.OK {
|
|
||||||
t.Fatalf("Get err %v; expected OK", err)
|
|
||||||
} else if val != Val {
|
|
||||||
t.Fatalf("Get value err %v; expected %v", val, Val)
|
|
||||||
} else if ver != Ver+1 {
|
|
||||||
t.Fatalf("Get wrong version %v; expected %v", ver, Ver+1)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := ck.Put("k", Val, 0); err != rpc.ErrVersion {
|
|
||||||
t.Fatalf("expected Put to fail with ErrVersion; got err=%v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := ck.Put("y", Val, rpc.Tversion(1)); err != rpc.ErrNoKey {
|
|
||||||
t.Fatalf("expected Put to fail with ErrNoKey; got err=%v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, _, err := ck.Get("y"); err != rpc.ErrNoKey {
|
|
||||||
t.Fatalf("expected Get to fail with ErrNoKey; got err=%v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Many clients putting on same key.
|
|
||||||
func TestPutConcurrentReliable(t *testing.T) {
|
|
||||||
const (
|
|
||||||
PORCUPINETIME = 10 * time.Second
|
|
||||||
NCLNT = 10
|
|
||||||
NSEC = 1
|
|
||||||
)
|
|
||||||
|
|
||||||
ts := MakeTestKV(t, true)
|
|
||||||
defer ts.Cleanup()
|
|
||||||
|
|
||||||
ts.Begin("Test: many clients racing to put values to the same key")
|
|
||||||
|
|
||||||
rs := ts.SpawnClientsAndWait(NCLNT, NSEC*time.Second, func(me int, ck kvtest.IKVClerk, done chan struct{}) kvtest.ClntRes {
|
|
||||||
return ts.OneClientPut(me, ck, []string{"k"}, done)
|
|
||||||
})
|
|
||||||
ck := ts.MakeClerk()
|
|
||||||
ts.CheckPutConcurrent(ck, "k", rs, &kvtest.ClntRes{})
|
|
||||||
ts.CheckPorcupineT(PORCUPINETIME)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if memory used on server is reasonable
|
|
||||||
func TestMemPutManyClientsReliable(t *testing.T) {
|
|
||||||
const (
|
|
||||||
NCLIENT = 100_000
|
|
||||||
MEM = 1000
|
|
||||||
)
|
|
||||||
|
|
||||||
ts := MakeTestKV(t, true)
|
|
||||||
defer ts.Cleanup()
|
|
||||||
|
|
||||||
v := kvtest.RandValue(MEM)
|
|
||||||
|
|
||||||
cks := make([]kvtest.IKVClerk, NCLIENT)
|
|
||||||
for i, _ := range cks {
|
|
||||||
cks[i] = ts.MakeClerk()
|
|
||||||
}
|
|
||||||
|
|
||||||
// force allocation of ends for server in each client
|
|
||||||
for i := 0; i < NCLIENT; i++ {
|
|
||||||
if err := cks[i].Put("k", "", 1); err != rpc.ErrNoKey {
|
|
||||||
t.Fatalf("Put failed %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ts.Begin("Test: memory use many put clients")
|
|
||||||
|
|
||||||
// allow threads started by labrpc to start
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
|
|
||||||
runtime.GC()
|
|
||||||
runtime.GC()
|
|
||||||
|
|
||||||
var st runtime.MemStats
|
|
||||||
runtime.ReadMemStats(&st)
|
|
||||||
m0 := st.HeapAlloc
|
|
||||||
|
|
||||||
for i := 0; i < NCLIENT; i++ {
|
|
||||||
if err := cks[i].Put("k", v, rpc.Tversion(i)); err != rpc.OK {
|
|
||||||
t.Fatalf("Put failed %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
runtime.GC()
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
runtime.GC()
|
|
||||||
|
|
||||||
runtime.ReadMemStats(&st)
|
|
||||||
m1 := st.HeapAlloc
|
|
||||||
f := (float64(m1) - float64(m0)) / NCLIENT
|
|
||||||
if m1 > m0+(NCLIENT*200) {
|
|
||||||
t.Fatalf("error: server using too much memory %d %d (%.2f per client)\n", m0, m1, f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test with one client and unreliable network. If Clerk.Put returns
|
|
||||||
// ErrMaybe, the Put must have happened, since the test uses only one
|
|
||||||
// client.
|
|
||||||
func TestUnreliableNet(t *testing.T) {
|
|
||||||
const NTRY = 100
|
|
||||||
|
|
||||||
ts := MakeTestKV(t, false)
|
|
||||||
defer ts.Cleanup()
|
|
||||||
|
|
||||||
ts.Begin("One client")
|
|
||||||
|
|
||||||
ck := ts.MakeClerk()
|
|
||||||
|
|
||||||
retried := false
|
|
||||||
for try := 0; try < NTRY; try++ {
|
|
||||||
for i := 0; true; i++ {
|
|
||||||
if err := ts.PutJson(ck, "k", i, rpc.Tversion(try), 0); err != rpc.ErrMaybe {
|
|
||||||
if i > 0 && err != rpc.ErrVersion {
|
|
||||||
t.Fatalf("Put shouldn't have happen more than once %v", err)
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
// Try put again; it should fail with ErrVersion
|
|
||||||
retried = true
|
|
||||||
}
|
|
||||||
v := 0
|
|
||||||
if ver := ts.GetJson(ck, "k", 0, &v); ver != rpc.Tversion(try+1) {
|
|
||||||
t.Fatalf("Wrong version %d expect %d", ver, try+1)
|
|
||||||
}
|
|
||||||
if v != 0 {
|
|
||||||
t.Fatalf("Wrong value %d expect %d", v, 0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !retried {
|
|
||||||
t.Fatalf("Clerk.Put never returned ErrMaybe")
|
|
||||||
}
|
|
||||||
|
|
||||||
ts.CheckPorcupine()
|
|
||||||
}
|
|
@ -1,31 +0,0 @@
|
|||||||
package lock
|
|
||||||
|
|
||||||
import (
|
|
||||||
|
|
||||||
"6.5840/kvsrv1/rpc"
|
|
||||||
"6.5840/shardkv1/kvsrv1"
|
|
||||||
"6.5840/shardkv1/shardctrler/param"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
type Lock struct {
|
|
||||||
ck *kvsrv.Clerk
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use l as the key to store the "lock state" (you would have to decide
|
|
||||||
// precisely what the lock state is).
|
|
||||||
func MakeLock(ck kvtest.IKVClerk, l string) *Lock {
|
|
||||||
lk := &Lock{ck: ck.(*kvsrv.Clerk)}
|
|
||||||
// You may add code here
|
|
||||||
return lk
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func (lk *Lock) Acquire() {
|
|
||||||
// You may add code here.
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lk *Lock) Release() {
|
|
||||||
// You may add code here.
|
|
||||||
}
|
|
@ -1,89 +0,0 @@
|
|||||||
package lock
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
// "log"
|
|
||||||
"strconv"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"6.5840/kvsrv1"
|
|
||||||
"6.5840/kvsrv1/rpc"
|
|
||||||
"6.5840/kvtest1"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
NACQUIRE = 10
|
|
||||||
NCLNT = 10
|
|
||||||
NSEC = 2
|
|
||||||
)
|
|
||||||
|
|
||||||
func oneClient(t *testing.T, me int, ck kvtest.IKVClerk, done chan struct{}) kvtest.ClntRes {
|
|
||||||
lk := MakeLock(ck, "l")
|
|
||||||
ck.Put("l0", "", 0)
|
|
||||||
for i := 1; true; i++ {
|
|
||||||
select {
|
|
||||||
case <-done:
|
|
||||||
return kvtest.ClntRes{i, 0}
|
|
||||||
default:
|
|
||||||
lk.Acquire()
|
|
||||||
|
|
||||||
// log.Printf("%d: acquired lock", me)
|
|
||||||
|
|
||||||
b := strconv.Itoa(me)
|
|
||||||
val, ver, err := ck.Get("l0")
|
|
||||||
if err == rpc.OK {
|
|
||||||
if val != "" {
|
|
||||||
t.Fatalf("%d: two clients acquired lock %v", me, val)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
t.Fatalf("%d: get failed %v", me, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = ck.Put("l0", string(b), ver)
|
|
||||||
if !(err == rpc.OK || err == rpc.ErrMaybe) {
|
|
||||||
t.Fatalf("%d: put failed %v", me, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
time.Sleep(10 * time.Millisecond)
|
|
||||||
|
|
||||||
err = ck.Put("l0", "", ver+1)
|
|
||||||
if !(err == rpc.OK || err == rpc.ErrMaybe) {
|
|
||||||
t.Fatalf("%d: put failed %v", me, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// log.Printf("%d: release lock", me)
|
|
||||||
|
|
||||||
lk.Release()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return kvtest.ClntRes{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run test clients
|
|
||||||
func runClients(t *testing.T, nclnt int, reliable bool) {
|
|
||||||
ts := kvsrv.MakeTestKV(t, reliable)
|
|
||||||
defer ts.Cleanup()
|
|
||||||
|
|
||||||
ts.Begin(fmt.Sprintf("Test: %d lock clients", nclnt))
|
|
||||||
|
|
||||||
ts.SpawnClientsAndWait(nclnt, NSEC*time.Second, func(me int, myck kvtest.IKVClerk, done chan struct{}) kvtest.ClntRes {
|
|
||||||
return oneClient(t, me, myck, done)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestOneClientReliable(t *testing.T) {
|
|
||||||
runClients(t, 1, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestManyClientsReliable(t *testing.T) {
|
|
||||||
runClients(t, NCLNT, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestOneClientUnreliable(t *testing.T) {
|
|
||||||
runClients(t, 1, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestManyClientsUnreliable(t *testing.T) {
|
|
||||||
runClients(t, NCLNT, false)
|
|
||||||
}
|
|
@ -1,48 +0,0 @@
|
|||||||
package kvsrv
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
|
|
||||||
"6.5840/kvsrv1/rpc"
|
|
||||||
"6.5840/labrpc"
|
|
||||||
"6.5840/tester1"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
type KVServer struct {
|
|
||||||
mu sync.Mutex
|
|
||||||
|
|
||||||
// Your definitions here.
|
|
||||||
}
|
|
||||||
|
|
||||||
func MakeKVServer() *KVServer {
|
|
||||||
kv := &KVServer{}
|
|
||||||
// Your code here.
|
|
||||||
return kv
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get returns the value and version for args.Key, if args.Key
|
|
||||||
// exists. Otherwise, Get returns ErrNoKey.
|
|
||||||
func (kv *KVServer) Get(args *rpc.GetArgs, reply *rpc.GetReply) {
|
|
||||||
// Your code here.
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the value for a key if args.Version matches the version of
|
|
||||||
// the key on the server. If versions don't match, return ErrVersion.
|
|
||||||
// If the key doesn't exist, Put installs the value if the
|
|
||||||
// args.Version is 0, and returns ErrNoKey otherwise.
|
|
||||||
func (kv *KVServer) Put(args *rpc.PutArgs, reply *rpc.PutReply) {
|
|
||||||
// Your code here.
|
|
||||||
}
|
|
||||||
|
|
||||||
// You can ignore Kill() for this lab
|
|
||||||
func (kv *KVServer) Kill() {
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// You can ignore all arguments; they are for replicated KVservers
|
|
||||||
func StartKVServer(ends []*labrpc.ClientEnd, gid tester.Tgid, srv int, persister *tester.Persister) []tester.IService {
|
|
||||||
kv := MakeKVServer()
|
|
||||||
return []tester.IService{kv}
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
package kvsrv
|
|
||||||
|
|
||||||
import (
|
|
||||||
// "log"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"6.5840/kvtest1"
|
|
||||||
"6.5840/tester1"
|
|
||||||
)
|
|
||||||
|
|
||||||
type TestKV struct {
|
|
||||||
*kvtest.Test
|
|
||||||
t *testing.T
|
|
||||||
reliable bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func MakeTestKV(t *testing.T, reliable bool) *TestKV {
|
|
||||||
cfg := tester.MakeConfig(t, 1, reliable, StartKVServer)
|
|
||||||
ts := &TestKV{
|
|
||||||
t: t,
|
|
||||||
reliable: reliable,
|
|
||||||
}
|
|
||||||
ts.Test = kvtest.MakeTest(t, cfg, false, ts)
|
|
||||||
return ts
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ts *TestKV) MakeClerk() kvtest.IKVClerk {
|
|
||||||
clnt := ts.Config.MakeClient()
|
|
||||||
ck := MakeClerk(clnt, tester.ServerName(tester.GRP0, 0))
|
|
||||||
return &kvtest.TestClerk{ck, clnt}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ts *TestKV) DeleteClerk(ck kvtest.IKVClerk) {
|
|
||||||
tck := ck.(*kvtest.TestClerk)
|
|
||||||
ts.DeleteClient(tck.Clnt)
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user