Full Code of wlgq2/MIT-6.824-2018 for AI

master 2d5887b6d975 cached
63 files
3.4 MB
889.3k tokens
560 symbols
1 requests
Download .txt
Showing preview only (3,560K chars total). Download the full file or copy to clipboard to get everything.
Repository: wlgq2/MIT-6.824-2018
Branch: master
Commit: 2d5887b6d975
Files: 63
Total size: 3.4 MB

Directory structure:
gitextract_7b5xu749/

├── LICENSE
├── Makefile
├── README.md
└── src/
    ├── .gitignore
    ├── kvraft/
    │   ├── client.go
    │   ├── common.go
    │   ├── config.go
    │   ├── server.go
    │   └── test_test.go
    ├── labgob/
    │   ├── labgob.go
    │   └── test_test.go
    ├── labrpc/
    │   ├── labrpc.go
    │   └── test_test.go
    ├── linearizability/
    │   ├── bitset.go
    │   ├── linearizability.go
    │   ├── model.go
    │   └── models.go
    ├── main/
    │   ├── diskvd.go
    │   ├── ii.go
    │   ├── lockc.go
    │   ├── lockd.go
    │   ├── mr-challenge.txt
    │   ├── mr-testout.txt
    │   ├── pbc.go
    │   ├── pbd.go
    │   ├── pg-being_ernest.txt
    │   ├── pg-dorian_gray.txt
    │   ├── pg-frankenstein.txt
    │   ├── pg-grimm.txt
    │   ├── pg-huckleberry_finn.txt
    │   ├── pg-metamorphosis.txt
    │   ├── pg-sherlock_holmes.txt
    │   ├── pg-tom_sawyer.txt
    │   ├── test-ii.sh
    │   ├── test-mr.sh
    │   ├── test-wc.sh
    │   ├── viewd.go
    │   └── wc.go
    ├── mapreduce/
    │   ├── common.go
    │   ├── common_map.go
    │   ├── common_reduce.go
    │   ├── common_rpc.go
    │   ├── master.go
    │   ├── master_rpc.go
    │   ├── master_splitmerge.go
    │   ├── schedule.go
    │   ├── test_test.go
    │   └── worker.go
    ├── raft/
    │   ├── config.go
    │   ├── persister.go
    │   ├── raft.go
    │   ├── test_test.go
    │   └── util.go
    ├── shardkv/
    │   ├── client.go
    │   ├── common.go
    │   ├── config.go
    │   ├── server.go
    │   └── test_test.go
    └── shardmaster/
        ├── client.go
        ├── common.go
        ├── config.go
        ├── server.go
        └── test_test.go

================================================
FILE CONTENTS
================================================

================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2019 莫失莫忘

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: Makefile
================================================
# This is the Makefile helping you submit the labs.  
# Just create 6.824/api.key with your API key in it, 
# and submit your lab with the following command: 
#     $ make [lab1|lab2a|lab2b|lab2c|lab3a|lab3b|lab4a|lab4b]

LABS=" lab1 lab2a lab2b lab2c lab3a lab3b lab4a lab4b "

%:
	@echo "Preparing $@-handin.tar.gz"
	@echo "Checking for committed temporary files..."
	@if git ls-files | grep -E 'mrtmp|mrinput' > /dev/null; then \
		echo "" ; \
		echo "OBS! You have committed some large temporary files:" ; \
		echo "" ; \
		git ls-files | grep -E 'mrtmp|mrinput' | sed 's/^/\t/' ; \
		echo "" ; \
		echo "Follow the instructions at http://stackoverflow.com/a/308684/472927" ; \
		echo "to remove them, and then run make again." ; \
		echo "" ; \
		exit 1 ; \
	fi
	@if echo $(LABS) | grep -q " $@ " ; then \
		echo "Tarring up your submission..." ; \
		tar cvzf $@-handin.tar.gz \
			"--exclude=src/main/pg-*.txt" \
			"--exclude=src/main/diskvd" \
			"--exclude=src/mapreduce/824-mrinput-*.txt" \
			"--exclude=mrtmp.*" \
			"--exclude=src/main/diff.out" \
			Makefile src; \
		if ! test -e api.key ; then \
			echo "Missing $(PWD)/api.key. Please create the file with your key in it or submit the $@-handin.tar.gz via the web interface."; \
		else \
			echo "Are you sure you want to submit $@? Enter 'yes' to continue:"; \
			read line; \
			if test "$$line" != "yes" ; then echo "Giving up submission"; exit; fi; \
			if test `stat -c "%s" "$@-handin.tar.gz" 2>/dev/null || stat -f "%z" "$@-handin.tar.gz"` -ge 20971520 ; then echo "File exceeds 20MB."; exit; fi; \
			mv api.key api.key.fix ; \
			cat api.key.fix | tr -d '\n' > api.key ; \
			rm api.key.fix ; \
			curl -F file=@$@-handin.tar.gz -F "key=<api.key" \
			https://6824.scripts.mit.edu/2018/handin.py/upload > /dev/null || { \
				echo ; \
				echo "Submit seems to have failed."; \
				echo "Please upload the tarball manually on the submission website."; } \
		fi; \
	else \
		echo "Bad target $@. Usage: make [$(LABS)]"; \
	fi


================================================
FILE: README.md
================================================
# MIT-6.824-2018
https://pdos.csail.mit.edu/6.824/

## Status
- [x] MapReduce
- [x] Raft
- [x] Raft K/V Service
- [x] Sharded K/V Service
  - [x] Part A
  - [x] Part B
  - [x] Challenge1
  - [x] Challenge2


================================================
FILE: src/.gitignore
================================================
*.*/
mrtmp.*
824-mrinput-*.txt
/main/diff.out
/mapreduce/x.txt
/pbservice/x.txt
/kvpaxos/x.txt


================================================
FILE: src/kvraft/client.go
================================================
package raftkv

import "labrpc"
import "crypto/rand"
import "math/big"
import "time"
import "sync/atomic"
import "log"

type Clerk struct {
	servers  []*labrpc.ClientEnd
	leaderId int
	me       int64 
	msgId    int64
}

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

func MakeClerk(servers []*labrpc.ClientEnd) *Clerk {
	ck := new(Clerk)
	ck.servers = servers
	ck.leaderId = 0
	ck.me = nrand()
	ck.msgId = 0
	return ck
}

func (ck *Clerk) Get(key string) string {
	req := GetArgs{
		Key: key,
	}
	for i:=0; i<8000; i++{
		resp := GetReply{}
		ok := ck.servers[ck.leaderId].Call("KVServer.Get", &req, &resp)
		if ok && !resp.WrongLeader {
			time.Sleep(time.Millisecond * 100)
			return resp.Value
		}
		ck.leaderId = (ck.leaderId + 1) % len(ck.servers)
		time.Sleep(time.Millisecond * 5)	
	}
	log.Fatalln("Get",key,"timeout")
	return ""
}

func (ck *Clerk) PutAppend(key string, value string, op string) {
	req := PutAppendArgs{
		Key:   key,
		Value: value,
		Op:    op,
		Me:  ck.me,
		MsgId : atomic.AddInt64(&ck.msgId, 1) ,
	}
	for i:=0; i<8000; i++ {
		resp := PutAppendReply{}
		ok := ck.servers[ck.leaderId].Call("KVServer.PutAppend", &req, &resp)
		if ok && !resp.WrongLeader {
			time.Sleep(time.Millisecond * 100)
			return
		}
		ck.leaderId = (ck.leaderId + 1) % len(ck.servers)
		time.Sleep(time.Millisecond * 5)
	}
	log.Fatalln(op,key,value,"timeout")
}

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


================================================
FILE: src/kvraft/common.go
================================================
package raftkv

const (
	OK       = "OK"
	ErrNoKey = "ErrNoKey"
)

type Err string

// Put or Append
type PutAppendArgs struct {
	Key   string
	Value string
	Op    string // "Put" or "Append"
	Me    int64
	MsgId int64
}

type PutAppendReply struct {
	WrongLeader bool
	Err         Err
}

type GetArgs struct {
	Key string
}

type GetReply struct {
	WrongLeader bool
	Err         Err
	Value       string
}


================================================
FILE: src/kvraft/config.go
================================================
package raftkv

import "labrpc"
import "testing"
import "os"

// import "log"
import crand "crypto/rand"
import "math/big"
import "math/rand"
import "encoding/base64"
import "sync"
import "runtime"
import "raft"
import "fmt"
import "time"
import "sync/atomic"

func randstring(n int) string {
	b := make([]byte, 2*n)
	crand.Read(b)
	s := base64.URLEncoding.EncodeToString(b)
	return s[0:n]
}

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

// Randomize server handles
func random_handles(kvh []*labrpc.ClientEnd) []*labrpc.ClientEnd {
	sa := make([]*labrpc.ClientEnd, len(kvh))
	copy(sa, kvh)
	for i := range sa {
		j := rand.Intn(i + 1)
		sa[i], sa[j] = sa[j], sa[i]
	}
	return sa
}

type config struct {
	mu           sync.Mutex
	t            *testing.T
	net          *labrpc.Network
	n            int
	kvservers    []*KVServer
	saved        []*raft.Persister
	endnames     [][]string // names of each server's sending ClientEnds
	clerks       map[*Clerk][]string
	nextClientId int
	maxraftstate int
	start        time.Time // time at which make_config() was called
	// begin()/end() statistics
	t0    time.Time // time at which test_test.go called cfg.begin()
	rpcs0 int       // rpcTotal() at start of test
	ops   int32     // number of clerk get/put/append method calls
}

func (cfg *config) checkTimeout() {
	// enforce a two minute real-time limit on each test
	if !cfg.t.Failed() && time.Since(cfg.start) > 120*time.Second {
		cfg.t.Fatal("test took longer than 120 seconds")
	}
}

func (cfg *config) cleanup() {
	cfg.mu.Lock()
	defer cfg.mu.Unlock()
	for i := 0; i < len(cfg.kvservers); i++ {
		if cfg.kvservers[i] != nil {
			cfg.kvservers[i].Kill()
		}
	}
	cfg.net.Cleanup()
	cfg.checkTimeout()
}

// Maximum log size across all servers
func (cfg *config) LogSize() int {
	logsize := 0
	for i := 0; i < cfg.n; i++ {
		n := cfg.saved[i].RaftStateSize()
		if n > logsize {
			logsize = n
		}
	}
	return logsize
}

// Maximum snapshot size across all servers
func (cfg *config) SnapshotSize() int {
	snapshotsize := 0
	for i := 0; i < cfg.n; i++ {
		n := cfg.saved[i].SnapshotSize()
		if n > snapshotsize {
			snapshotsize = n
		}
	}
	return snapshotsize
}

// attach server i to servers listed in to
// caller must hold cfg.mu
func (cfg *config) connectUnlocked(i int, to []int) {
	// log.Printf("connect peer %d to %v\n", i, to)

	// outgoing socket files
	for j := 0; j < len(to); j++ {
		endname := cfg.endnames[i][to[j]]
		cfg.net.Enable(endname, true)
	}

	// incoming socket files
	for j := 0; j < len(to); j++ {
		endname := cfg.endnames[to[j]][i]
		cfg.net.Enable(endname, true)
	}
}

func (cfg *config) connect(i int, to []int) {
	cfg.mu.Lock()
	defer cfg.mu.Unlock()
	cfg.connectUnlocked(i, to)
}

// detach server i from the servers listed in from
// caller must hold cfg.mu
func (cfg *config) disconnectUnlocked(i int, from []int) {
	// log.Printf("disconnect peer %d from %v\n", i, from)

	// outgoing socket files
	for j := 0; j < len(from); j++ {
		if cfg.endnames[i] != nil {
			endname := cfg.endnames[i][from[j]]
			cfg.net.Enable(endname, false)
		}
	}

	// incoming socket files
	for j := 0; j < len(from); j++ {
		if cfg.endnames[j] != nil {
			endname := cfg.endnames[from[j]][i]
			cfg.net.Enable(endname, false)
		}
	}
}

func (cfg *config) disconnect(i int, from []int) {
	cfg.mu.Lock()
	defer cfg.mu.Unlock()
	cfg.disconnectUnlocked(i, from)
}

func (cfg *config) All() []int {
	all := make([]int, cfg.n)
	for i := 0; i < cfg.n; i++ {
		all[i] = i
	}
	return all
}

func (cfg *config) ConnectAll() {
	cfg.mu.Lock()
	defer cfg.mu.Unlock()
	for i := 0; i < cfg.n; i++ {
		cfg.connectUnlocked(i, cfg.All())
	}
}

// Sets up 2 partitions with connectivity between servers in each  partition.
func (cfg *config) partition(p1 []int, p2 []int) {
	cfg.mu.Lock()
	defer cfg.mu.Unlock()
	// log.Printf("partition servers into: %v %v\n", p1, p2)
	for i := 0; i < len(p1); i++ {
		cfg.disconnectUnlocked(p1[i], p2)
		cfg.connectUnlocked(p1[i], p1)
	}
	for i := 0; i < len(p2); i++ {
		cfg.disconnectUnlocked(p2[i], p1)
		cfg.connectUnlocked(p2[i], p2)
	}
}

// Create a clerk with clerk specific server names.
// Give it connections to all of the servers, but for
// now enable only connections to servers in to[].
func (cfg *config) makeClient(to []int) *Clerk {
	cfg.mu.Lock()
	defer cfg.mu.Unlock()

	// a fresh set of ClientEnds.
	ends := make([]*labrpc.ClientEnd, cfg.n)
	endnames := make([]string, cfg.n)
	for j := 0; j < cfg.n; j++ {
		endnames[j] = randstring(20)
		ends[j] = cfg.net.MakeEnd(endnames[j])
		cfg.net.Connect(endnames[j], j)
	}

	ck := MakeClerk(random_handles(ends))
	cfg.clerks[ck] = endnames
	cfg.nextClientId++
	cfg.ConnectClientUnlocked(ck, to)
	return ck
}

func (cfg *config) deleteClient(ck *Clerk) {
	cfg.mu.Lock()
	defer cfg.mu.Unlock()

	v := cfg.clerks[ck]
	for i := 0; i < len(v); i++ {
		os.Remove(v[i])
	}
	delete(cfg.clerks, ck)
}

// caller should hold cfg.mu
func (cfg *config) ConnectClientUnlocked(ck *Clerk, to []int) {
	// log.Printf("ConnectClient %v to %v\n", ck, to)
	endnames := cfg.clerks[ck]
	for j := 0; j < len(to); j++ {
		s := endnames[to[j]]
		cfg.net.Enable(s, true)
	}
}

func (cfg *config) ConnectClient(ck *Clerk, to []int) {
	cfg.mu.Lock()
	defer cfg.mu.Unlock()
	cfg.ConnectClientUnlocked(ck, to)
}

// caller should hold cfg.mu
func (cfg *config) DisconnectClientUnlocked(ck *Clerk, from []int) {
	// log.Printf("DisconnectClient %v from %v\n", ck, from)
	endnames := cfg.clerks[ck]
	for j := 0; j < len(from); j++ {
		s := endnames[from[j]]
		cfg.net.Enable(s, false)
	}
}

func (cfg *config) DisconnectClient(ck *Clerk, from []int) {
	cfg.mu.Lock()
	defer cfg.mu.Unlock()
	cfg.DisconnectClientUnlocked(ck, from)
}

// Shutdown a server by isolating it
func (cfg *config) ShutdownServer(i int) {
	cfg.mu.Lock()
	defer cfg.mu.Unlock()

	cfg.disconnectUnlocked(i, cfg.All())

	// disable client connections to the server.
	// it's important to do this before creating
	// the new Persister in saved[i], to avoid
	// the possibility of the server returning a
	// positive reply to an Append but persisting
	// the result in the superseded Persister.
	cfg.net.DeleteServer(i)

	// a fresh persister, in case old instance
	// continues to update the Persister.
	// but copy old persister's content so that we always
	// pass Make() the last persisted state.
	if cfg.saved[i] != nil {
		cfg.saved[i] = cfg.saved[i].Copy()
	}

	kv := cfg.kvservers[i]
	if kv != nil {
		cfg.mu.Unlock()
		kv.Kill()
		cfg.mu.Lock()
		cfg.kvservers[i] = nil
	}
}

// If restart servers, first call ShutdownServer
func (cfg *config) StartServer(i int) {
	cfg.mu.Lock()

	// a fresh set of outgoing ClientEnd names.
	cfg.endnames[i] = make([]string, cfg.n)
	for j := 0; j < cfg.n; j++ {
		cfg.endnames[i][j] = randstring(20)
	}

	// a fresh set of ClientEnds.
	ends := make([]*labrpc.ClientEnd, cfg.n)
	for j := 0; j < cfg.n; j++ {
		ends[j] = cfg.net.MakeEnd(cfg.endnames[i][j])
		cfg.net.Connect(cfg.endnames[i][j], j)
	}

	// a fresh persister, so old instance doesn't overwrite
	// new instance's persisted state.
	// give the fresh persister a copy of the old persister's
	// state, so that the spec is that we pass StartKVServer()
	// the last persisted state.
	if cfg.saved[i] != nil {
		cfg.saved[i] = cfg.saved[i].Copy()
	} else {
		cfg.saved[i] = raft.MakePersister()
	}
	cfg.mu.Unlock()

	cfg.kvservers[i] = StartKVServer(ends, i, cfg.saved[i], cfg.maxraftstate)

	kvsvc := labrpc.MakeService(cfg.kvservers[i])
	rfsvc := labrpc.MakeService(cfg.kvservers[i].rf)
	srv := labrpc.MakeServer()
	srv.AddService(kvsvc)
	srv.AddService(rfsvc)
	cfg.net.AddServer(i, srv)
}

func (cfg *config) Leader() (bool, int) {
	cfg.mu.Lock()
	defer cfg.mu.Unlock()

	for i := 0; i < cfg.n; i++ {
		_, is_leader := cfg.kvservers[i].rf.GetState()
		if is_leader {
			return true, i
		}
	}
	return false, 0
}

// Partition servers into 2 groups and put current leader in minority
func (cfg *config) make_partition() ([]int, []int) {
	_, l := cfg.Leader()
	p1 := make([]int, cfg.n/2+1)
	p2 := make([]int, cfg.n/2)
	j := 0
	for i := 0; i < cfg.n; i++ {
		if i != l {
			if j < len(p1) {
				p1[j] = i
			} else {
				p2[j-len(p1)] = i
			}
			j++
		}
	}
	p2[len(p2)-1] = l
	return p1, p2
}

var ncpu_once sync.Once

func make_config(t *testing.T, n int, unreliable bool, maxraftstate int) *config {
	ncpu_once.Do(func() {
		if runtime.NumCPU() < 2 {
			fmt.Printf("warning: only one CPU, which may conceal locking bugs\n")
		}
		rand.Seed(makeSeed())
	})
	runtime.GOMAXPROCS(4)
	cfg := &config{}
	cfg.t = t
	cfg.net = labrpc.MakeNetwork()
	cfg.n = n
	cfg.kvservers = make([]*KVServer, cfg.n)
	cfg.saved = make([]*raft.Persister, cfg.n)
	cfg.endnames = make([][]string, cfg.n)
	cfg.clerks = make(map[*Clerk][]string)
	cfg.nextClientId = cfg.n + 1000 // client ids start 1000 above the highest serverid
	cfg.maxraftstate = maxraftstate
	cfg.start = time.Now()

	// create a full set of KV servers.
	for i := 0; i < cfg.n; i++ {
		cfg.StartServer(i)
	}

	cfg.ConnectAll()

	cfg.net.Reliable(!unreliable)

	return cfg
}

func (cfg *config) rpcTotal() int {
	return cfg.net.GetTotalCount()
}

// start a Test.
// print the Test message.
// e.g. cfg.begin("Test (2B): RPC counts aren't too high")
func (cfg *config) begin(description string) {
	fmt.Printf("%s ...\n", description)
	cfg.t0 = time.Now()
	cfg.rpcs0 = cfg.rpcTotal()
	atomic.StoreInt32(&cfg.ops, 0)
}

func (cfg *config) op() {
	atomic.AddInt32(&cfg.ops, 1)
}

// end a Test -- the fact that we got here means there
// was no failure.
// print the Passed message,
// and some performance numbers.
func (cfg *config) end() {
	cfg.checkTimeout()
	if cfg.t.Failed() == false {
		t := time.Since(cfg.t0).Seconds()  // real time
		npeers := cfg.n                    // number of Raft peers
		nrpc := cfg.rpcTotal() - cfg.rpcs0 // number of RPC sends
		ops := atomic.LoadInt32(&cfg.ops)  //  number of clerk get/put/append calls

		fmt.Printf("  ... Passed --")
		fmt.Printf("  %4.1f  %d %5d %4d\n", t, npeers, nrpc, ops)
	}
}


================================================
FILE: src/kvraft/server.go
================================================
package raftkv

import (
	"labgob"
	"labrpc"
	"log"
	"raft"
	"sync"
	"time"
	"bytes"
)

type Op struct {
	Ch  chan (interface{})
	Req interface{}
}

var kvOnce sync.Once

type KVServer struct {
	mu      sync.Mutex 
	me      int
	rf      *raft.Raft
	applyCh chan raft.ApplyMsg
	maxraftstate int // snapshot if log grows this big
	kvs            map[string]string
	msgIDs         map[int64] int64
	killChan       chan (bool)
	persister      *raft.Persister
	logApplyIndex  int
	EnableDebugLog bool
}

func (kv *KVServer) println(args ...interface{}) {
	if kv.EnableDebugLog {
		log.Println(args...)
	}
}
//raft操作
func (kv *KVServer) opt(client int64,msgId int64,req interface{}) (bool,interface{}) {
	if msgId > 0 && kv.isRepeated(client,msgId,false) { //去重
		return true,nil
	}
	op := Op {
		Req : req, //请求数据
		Ch : make(chan(interface{})), //日志提交chan
	}
	_, _, isLeader := kv.rf.Start(op) //写入Raft
	if !isLeader {  //判定是否是leader
		return false,nil  
	}
	select {
		case resp := <-op.Ch:
			return true,resp
		case <-time.After(time.Millisecond * 1000): //超时
	}
	return false,nil
}
//读请求
func (kv *KVServer) Get(req *GetArgs, reply *GetReply) {
	ok,value := kv.opt(-1,-1,*req)
	reply.WrongLeader = !ok
	if ok {
		reply.Value = value.(string)
	}
}
//写请求
func (kv *KVServer) PutAppend(req *PutAppendArgs, reply *PutAppendReply) {
	ok,_ := kv.opt(req.Me,req.MsgId,*req)
	reply.WrongLeader = !ok
}
//写操作
func (kv *KVServer) putAppend(req *PutAppendArgs) {
	kv.println(kv.me,"on",req.Op,req.Key,":",req.Value)
	if req.Op == "Put" {
		kv.kvs[req.Key] = req.Value
	} else if req.Op == "Append" {
		value, ok := kv.kvs[req.Key]
		if !ok {
			value = ""
		}
		value += req.Value
		kv.kvs[req.Key] = value
	}
}
//读操作
func (kv *KVServer) get(args *GetArgs) (value string) {
	value, ok := kv.kvs[args.Key]
	if !ok {
		value = ""
	}
	kv.println(kv.me,"on get",args.Key,":",value)
	return 
}

func (kv *KVServer) Kill() {
	kv.rf.Kill()
	kv.killChan <- true
}

//判定重复请求
func (kv *KVServer) isRepeated(client int64,msgId int64,update bool) bool {
	kv.mu.Lock()
	defer kv.mu.Unlock()
	rst := false
	index,ok := kv.msgIDs[client]
	if ok {
		rst = index >= msgId
	}
	if update && !rst {
		kv.msgIDs[client] = msgId
	}
	return rst
}
//判定是否写入快照
func  (kv *KVServer) ifSaveSnapshot() {
	if kv.maxraftstate != -1 && kv.persister.RaftStateSize() >= kv.maxraftstate {
		writer := new(bytes.Buffer)
		encoder := labgob.NewEncoder(writer)
		encoder.Encode(kv.msgIDs)
		encoder.Encode(kv.kvs)
		data := writer.Bytes()
		kv.rf.SaveSnapshot(kv.logApplyIndex,data)
		return 
	}
}
//更新快照
func  (kv *KVServer) updateSnapshot(index int,data []byte) {
	if data == nil || len(data) < 1 {
		return
	}
	kv.logApplyIndex = index
	reader := bytes.NewBuffer(data)
	decoder := labgob.NewDecoder(reader)

	if decoder.Decode(&kv.msgIDs) != nil ||
		decoder.Decode(&kv.kvs) != nil  {
		kv.println("Error in unmarshal raft state")
	} 
}
//apply 状态机
func (kv *KVServer) onApply(applyMsg raft.ApplyMsg) {
	if !applyMsg.CommandValid {  //非状态机apply消息
		if command, ok := applyMsg.Command.(raft.LogSnapshot); ok { //更新快照消息
			kv.updateSnapshot(command.Index,command.Datas)
		} 
		kv.ifSaveSnapshot()
		return
	}
	//更新日志索引,用于创建最新快照
	kv.logApplyIndex = applyMsg.CommandIndex
	opt := applyMsg.Command.(Op)
	var resp interface{}
	if command, ok := opt.Req.(PutAppendArgs); ok { //Put && append操作
		if !kv.isRepeated(command.Me,command.MsgId,true) { //去重复
			kv.putAppend(&command)
		}
		resp = true
	} else { //Get操作
		command := opt.Req.(GetArgs)
		resp = kv.get(&command)
	}
	select {
		case opt.Ch <- resp :
		default:
	}	
	kv.ifSaveSnapshot()
}

//轮询
func (kv *KVServer) mainLoop() {
	for {
		select {
		case <-kv.killChan:
			return
		case msg := <-kv.applyCh:
			if cap(kv.applyCh) - len(kv.applyCh) < 5 {
				log.Println("warn : maybe dead lock...")
			}
			kv.onApply(msg)
		}
	}
}

func StartKVServer(servers []*labrpc.ClientEnd, me int, persister *raft.Persister, maxraftstate int) *KVServer {
	kv := new(KVServer)
	kv.me = me
	kv.maxraftstate = maxraftstate
	kv.applyCh = make(chan raft.ApplyMsg, 10000)
	kv.kvs = make(map[string]string)
	kv.msgIDs = make(map[int64]int64)
	kv.killChan = make(chan (bool))
	kv.persister = persister
	kv.EnableDebugLog = false
	kv.logApplyIndex = 0
	kvOnce.Do(func() {
		labgob.Register(Op{})
		labgob.Register(PutAppendArgs{})
		labgob.Register(GetArgs{})
	})
	go kv.mainLoop()
	kv.rf = raft.Make(servers, me, persister, kv.applyCh)
	kv.rf.EnableDebugLog = false
	return kv
}


================================================
FILE: src/kvraft/test_test.go
================================================
package raftkv

import "linearizability"

import "testing"
import "strconv"
import "time"
import "math/rand"
import "log"
import "strings"
import "sync"
import "sync/atomic"

// The tester generously allows solutions to complete elections in one second
// (much more than the paper's range of timeouts).
const electionTimeout = 1 * time.Second

const linearizabilityCheckTimeout = 1 * time.Second

// get/put/putappend that keep counts
func Get(cfg *config, ck *Clerk, key string) string {
	v := ck.Get(key)
	cfg.op()
	return v
}

func Put(cfg *config, ck *Clerk, key string, value string) {
	ck.Put(key, value)
	cfg.op()
}

func Append(cfg *config, ck *Clerk, key string, value string) {
	ck.Append(key, value)
	cfg.op()
}

func check(cfg *config, t *testing.T, ck *Clerk, key string, value string) {
	v := Get(cfg, ck, key)
	if v != value {
		t.Fatalf("Get(%v): expected:\n%v\nreceived:\n%v", key, value, v)
	}
}

// a client runs the function f and then signals it is done
func run_client(t *testing.T, cfg *config, me int, ca chan bool, fn func(me int, ck *Clerk, t *testing.T)) {
	ok := false
	defer func() { ca <- ok }()
	ck := cfg.makeClient(cfg.All())
	fn(me, ck, t)
	ok = true
	cfg.deleteClient(ck)
}

// spawn ncli clients and wait until they are all done
func spawn_clients_and_wait(t *testing.T, cfg *config, ncli int, fn func(me int, ck *Clerk, t *testing.T)) {
	ca := make([]chan bool, ncli)
	for cli := 0; cli < ncli; cli++ {
		ca[cli] = make(chan bool)
		go run_client(t, cfg, cli, ca[cli], fn)
	}
	// log.Printf("spawn_clients_and_wait: waiting for clients")
	for cli := 0; cli < ncli; cli++ {
		ok := <-ca[cli]
		// log.Printf("spawn_clients_and_wait: client %d is done\n", cli)
		if ok == false {
			t.Fatalf("failure")
		}
	}
}

// predict effect of Append(k, val) if old value is prev.
func NextValue(prev string, val string) string {
	return prev + val
}

// check that for a specific client all known appends are present in a value,
// and in order
func checkClntAppends(t *testing.T, clnt int, v string, count int) {
	lastoff := -1
	for j := 0; j < count; j++ {
		wanted := "x " + strconv.Itoa(clnt) + " " + strconv.Itoa(j) + " y"
		off := strings.Index(v, wanted)
		if off < 0 {
			t.Fatalf("%v missing element %v in Append result %v", clnt, wanted, v)
		}
		off1 := strings.LastIndex(v, wanted)
		if off1 != off {
			t.Fatalf("duplicate element %v in Append result", wanted)
		}
		if off <= lastoff {
			t.Fatalf("wrong order for element %v in Append result", wanted)
		}
		lastoff = off
	}
}

// check that all known appends are present in a value,
// and are in order for each concurrent client.
func checkConcurrentAppends(t *testing.T, v string, counts []int) {
	nclients := len(counts)
	for i := 0; i < nclients; i++ {
		lastoff := -1
		for j := 0; j < counts[i]; j++ {
			wanted := "x " + strconv.Itoa(i) + " " + strconv.Itoa(j) + " y"
			off := strings.Index(v, wanted)
			if off < 0 {
				t.Fatalf("%v missing element %v in Append result %v", i, wanted, v)
			}
			off1 := strings.LastIndex(v, wanted)
			if off1 != off {
				t.Fatalf("duplicate element %v in Append result", wanted)
			}
			if off <= lastoff {
				t.Fatalf("wrong order for element %v in Append result", wanted)
			}
			lastoff = off
		}
	}
}

// repartition the servers periodically
func partitioner(t *testing.T, cfg *config, ch chan bool, done *int32) {
	defer func() { ch <- true }()
	for atomic.LoadInt32(done) == 0 {
		a := make([]int, cfg.n)
		for i := 0; i < cfg.n; i++ {
			a[i] = (rand.Int() % 2)
		}
		pa := make([][]int, 2)
		for i := 0; i < 2; i++ {
			pa[i] = make([]int, 0)
			for j := 0; j < cfg.n; j++ {
				if a[j] == i {
					pa[i] = append(pa[i], j)
				}
			}
		}
		cfg.partition(pa[0], pa[1])
		time.Sleep(electionTimeout + time.Duration(rand.Int63()%200)*time.Millisecond)
	}
}

// Basic test is as follows: one or more clients submitting Append/Get
// operations to set of servers for some period of time.  After the period is
// over, test checks that all appended values are present and in order for a
// particular key.  If unreliable is set, RPCs may fail.  If crash is set, the
// servers crash after the period is over and restart.  If partitions is set,
// the test repartitions the network concurrently with the clients and servers. If
// maxraftstate is a positive number, the size of the state for Raft (i.e., log
// size) shouldn't exceed 2*maxraftstate.
func GenericTest(t *testing.T, part string, nclients int, unreliable bool, crash bool, partitions bool, maxraftstate int) {

	title := "Test: "
	if unreliable {
		// the network drops RPC requests and replies.
		title = title + "unreliable net, "
	}
	if crash {
		// peers re-start, and thus persistence must work.
		title = title + "restarts, "
	}
	if partitions {
		// the network may partition
		title = title + "partitions, "
	}
	if maxraftstate != -1 {
		title = title + "snapshots, "
	}
	if nclients > 1 {
		title = title + "many clients"
	} else {
		title = title + "one client"
	}
	title = title + " (" + part + ")" // 3A or 3B

	const nservers = 5
	cfg := make_config(t, nservers, unreliable, maxraftstate)
	defer cfg.cleanup()

	cfg.begin(title)

	ck := cfg.makeClient(cfg.All())

	done_partitioner := int32(0)
	done_clients := int32(0)
	ch_partitioner := make(chan bool)
	clnts := make([]chan int, nclients)
	for i := 0; i < nclients; i++ {
		clnts[i] = make(chan int)
	}
	for i := 0; i < 3; i++ {
		// log.Printf("Iteration %v\n", i)
		atomic.StoreInt32(&done_clients, 0)
		atomic.StoreInt32(&done_partitioner, 0)
		go spawn_clients_and_wait(t, cfg, nclients, func(cli int, myck *Clerk, t *testing.T) {
			j := 0
			defer func() {
				clnts[cli] <- j
			}()
			last := ""
			key := strconv.Itoa(cli)
			Put(cfg, myck, key, last)
			for atomic.LoadInt32(&done_clients) == 0 {
				if (rand.Int() % 1000) < 500 {
					nv := "x " + strconv.Itoa(cli) + " " + strconv.Itoa(j) + " y"
					// log.Printf("%d: client new append %v\n", cli, nv)
					Append(cfg, myck, key, nv)
					last = NextValue(last, nv)
					j++
				} else {
					// log.Printf("%d: client new get %v\n", cli, key)
					v := Get(cfg, myck, key)
					if v != last {
						log.Fatalf("get wrong value, key %v, wanted:\n%v\n, got\n%v\n", key, last, v)
					}
				}
			}
		})

		if partitions {
			// Allow the clients to perform some operations without interruption
			time.Sleep(1 * time.Second)
			go partitioner(t, cfg, ch_partitioner, &done_partitioner)
		}
		time.Sleep(5 * time.Second)

		atomic.StoreInt32(&done_clients, 1)     // tell clients to quit
		atomic.StoreInt32(&done_partitioner, 1) // tell partitioner to quit

		if partitions {
			// log.Printf("wait for partitioner\n")
			<-ch_partitioner
			// reconnect network and submit a request. A client may
			// have submitted a request in a minority.  That request
			// won't return until that server discovers a new term
			// has started.
			cfg.ConnectAll()
			// wait for a while so that we have a new term
			time.Sleep(electionTimeout)
		}

		if crash {
			// log.Printf("shutdown servers\n")
			for i := 0; i < nservers; i++ {
				cfg.ShutdownServer(i)
			}
			// Wait for a while for servers to shutdown, since
			// shutdown isn't a real crash and isn't instantaneous
			time.Sleep(electionTimeout)
			// log.Printf("restart servers\n")
			// crash and re-start all
			for i := 0; i < nservers; i++ {
				cfg.StartServer(i)
			}
			cfg.ConnectAll()
		}

		// log.Printf("wait for clients\n")
		for i := 0; i < nclients; i++ {
			// log.Printf("read from clients %d\n", i)
			j := <-clnts[i]
			// if j < 10 {
			// 	log.Printf("Warning: client %d managed to perform only %d put operations in 1 sec?\n", i, j)
			// }
			key := strconv.Itoa(i)
			// log.Printf("Check %v for client %d\n", j, i)
			v := Get(cfg, ck, key)
			checkClntAppends(t, i, v, j)
		}

		if maxraftstate > 0 {
			// Check maximum after the servers have processed all client
			// requests and had time to checkpoint.
			if cfg.LogSize() > 2*maxraftstate {
				t.Fatalf("logs were not trimmed (%v > 2*%v)", cfg.LogSize(), maxraftstate)
			}
		}
	}

	cfg.end()
}

// similar to GenericTest, but with clients doing random operations (and using a
// linearizability checker)
func GenericTestLinearizability(t *testing.T, part string, nclients int, nservers int, unreliable bool, crash bool, partitions bool, maxraftstate int) {

	title := "Test: "
	if unreliable {
		// the network drops RPC requests and replies.
		title = title + "unreliable net, "
	}
	if crash {
		// peers re-start, and thus persistence must work.
		title = title + "restarts, "
	}
	if partitions {
		// the network may partition
		title = title + "partitions, "
	}
	if maxraftstate != -1 {
		title = title + "snapshots, "
	}
	if nclients > 1 {
		title = title + "many clients"
	} else {
		title = title + "one client"
	}
	title = title + ", linearizability checks (" + part + ")" // 3A or 3B

	cfg := make_config(t, nservers, unreliable, maxraftstate)
	defer cfg.cleanup()

	cfg.begin(title)

	begin := time.Now()
	var operations []linearizability.Operation
	var opMu sync.Mutex

	done_partitioner := int32(0)
	done_clients := int32(0)
	ch_partitioner := make(chan bool)
	clnts := make([]chan int, nclients)
	for i := 0; i < nclients; i++ {
		clnts[i] = make(chan int)
	}
	for i := 0; i < 3; i++ {
		// log.Printf("Iteration %v\n", i)
		atomic.StoreInt32(&done_clients, 0)
		atomic.StoreInt32(&done_partitioner, 0)
		go spawn_clients_and_wait(t, cfg, nclients, func(cli int, myck *Clerk, t *testing.T) {
			j := 0
			defer func() {
				clnts[cli] <- j
			}()
			for atomic.LoadInt32(&done_clients) == 0 {
				key := strconv.Itoa(rand.Int() % nclients)
				nv := "x " + strconv.Itoa(cli) + " " + strconv.Itoa(j) + " y"
				var inp linearizability.KvInput
				var out linearizability.KvOutput
				start := int64(time.Since(begin))
				if (rand.Int() % 1000) < 500 {
					Append(cfg, myck, key, nv)
					inp = linearizability.KvInput{Op: 2, Key: key, Value: nv}
					j++
				} else if (rand.Int() % 1000) < 100 {
					Put(cfg, myck, key, nv)
					inp = linearizability.KvInput{Op: 1, Key: key, Value: nv}
					j++
				} else {
					v := Get(cfg, myck, key)
					inp = linearizability.KvInput{Op: 0, Key: key}
					out = linearizability.KvOutput{Value: v}
				}
				end := int64(time.Since(begin))
				op := linearizability.Operation{Input: inp, Call: start, Output: out, Return: end}
				opMu.Lock()
				operations = append(operations, op)
				opMu.Unlock()
			}
		})

		if partitions {
			// Allow the clients to perform some operations without interruption
			time.Sleep(1 * time.Second)
			go partitioner(t, cfg, ch_partitioner, &done_partitioner)
		}
		time.Sleep(5 * time.Second)

		atomic.StoreInt32(&done_clients, 1)     // tell clients to quit
		atomic.StoreInt32(&done_partitioner, 1) // tell partitioner to quit

		if partitions {
			// log.Printf("wait for partitioner\n")
			<-ch_partitioner
			// reconnect network and submit a request. A client may
			// have submitted a request in a minority.  That request
			// won't return until that server discovers a new term
			// has started.
			cfg.ConnectAll()
			// wait for a while so that we have a new term
			time.Sleep(electionTimeout)
		}

		if crash {
			// log.Printf("shutdown servers\n")
			for i := 0; i < nservers; i++ {
				cfg.ShutdownServer(i)
			}
			// Wait for a while for servers to shutdown, since
			// shutdown isn't a real crash and isn't instantaneous
			time.Sleep(electionTimeout)
			// log.Printf("restart servers\n")
			// crash and re-start all
			for i := 0; i < nservers; i++ {
				cfg.StartServer(i)
			}
			cfg.ConnectAll()
		}

		// wait for clients.
		for i := 0; i < nclients; i++ {
			<-clnts[i]
		}

		if maxraftstate > 0 {
			// Check maximum after the servers have processed all client
			// requests and had time to checkpoint.
			if cfg.LogSize() > 2*maxraftstate {
				t.Fatalf("logs were not trimmed (%v > 2*%v)", cfg.LogSize(), maxraftstate)
			}
		}
	}

	cfg.end()

	// log.Printf("Checking linearizability of %d operations", len(operations))
	// start := time.Now()
	ok := linearizability.CheckOperationsTimeout(linearizability.KvModel(), operations, linearizabilityCheckTimeout)
	// dur := time.Since(start)
	// log.Printf("Linearizability check done in %s; result: %t", time.Since(start).String(), ok)
	if !ok {
		t.Fatal("history is not linearizable")
	}
}

func TestBasic3A(t *testing.T) {
	// Test: one client (3A) ...
	GenericTest(t, "3A", 1, false, false, false, -1)
}

func TestConcurrent3A(t *testing.T) {
	// Test: many clients (3A) ...
	GenericTest(t, "3A", 5, false, false, false, -1)
}

func TestUnreliable3A(t *testing.T) {
	// Test: unreliable net, many clients (3A) ...
	GenericTest(t, "3A", 5, true, false, false, -1)
}

func TestUnreliableOneKey3A(t *testing.T) {
	const nservers = 3
	cfg := make_config(t, nservers, true, -1)
	defer cfg.cleanup()

	ck := cfg.makeClient(cfg.All())

	cfg.begin("Test: concurrent append to same key, unreliable (3A)")

	Put(cfg, ck, "k", "")

	const nclient = 5
	const upto = 10
	spawn_clients_and_wait(t, cfg, nclient, func(me int, myck *Clerk, t *testing.T) {
		n := 0
		for n < upto {
			Append(cfg, myck, "k", "x "+strconv.Itoa(me)+" "+strconv.Itoa(n)+" y")
			n++
		}
	})

	var counts []int
	for i := 0; i < nclient; i++ {
		counts = append(counts, upto)
	}

	vx := Get(cfg, ck, "k")
	checkConcurrentAppends(t, vx, counts)

	cfg.end()
}

// Submit a request in the minority partition and check that the requests
// doesn't go through until the partition heals.  The leader in the original
// network ends up in the minority partition.
func TestOnePartition3A(t *testing.T) {
	const nservers = 5
	cfg := make_config(t, nservers, false, -1)
	defer cfg.cleanup()
	ck := cfg.makeClient(cfg.All())

	Put(cfg, ck, "1", "13")

	cfg.begin("Test: progress in majority (3A)")

	p1, p2 := cfg.make_partition()
	cfg.partition(p1, p2)

	ckp1 := cfg.makeClient(p1)  // connect ckp1 to p1
	ckp2a := cfg.makeClient(p2) // connect ckp2a to p2
	ckp2b := cfg.makeClient(p2) // connect ckp2b to p2

	Put(cfg, ckp1, "1", "14")
	check(cfg, t, ckp1, "1", "14")

	cfg.end()

	done0 := make(chan bool)
	done1 := make(chan bool)

	cfg.begin("Test: no progress in minority (3A)")
	go func() {
		Put(cfg, ckp2a, "1", "15")
		done0 <- true
	}()
	go func() {
		Get(cfg, ckp2b, "1") // different clerk in p2
		done1 <- true
	}()

	select {
	case <-done0:
		t.Fatalf("Put in minority completed")
	case <-done1:
		t.Fatalf("Get in minority completed")
	case <-time.After(time.Second):
	}

	check(cfg, t, ckp1, "1", "14")
	Put(cfg, ckp1, "1", "16")
	check(cfg, t, ckp1, "1", "16")

	cfg.end()

	cfg.begin("Test: completion after heal (3A)")

	cfg.ConnectAll()
	cfg.ConnectClient(ckp2a, cfg.All())
	cfg.ConnectClient(ckp2b, cfg.All())

	time.Sleep(electionTimeout)

	select {
	case <-done0:
	case <-time.After(30 * 100 * time.Millisecond):
		t.Fatalf("Put did not complete")
	}

	select {
	case <-done1:
	case <-time.After(30 * 100 * time.Millisecond):
		t.Fatalf("Get did not complete")
	default:
	}

	check(cfg, t, ck, "1", "15")

	cfg.end()
}

func TestManyPartitionsOneClient3A(t *testing.T) {
	// Test: partitions, one client (3A) ...
	GenericTest(t, "3A", 1, false, false, true, -1)
}

func TestManyPartitionsManyClients3A(t *testing.T) {
	// Test: partitions, many clients (3A) ...
	GenericTest(t, "3A", 5, false, false, true, -1)
}

func TestPersistOneClient3A(t *testing.T) {
	// Test: restarts, one client (3A) ...
	GenericTest(t, "3A", 1, false, true, false, -1)
}

func TestPersistConcurrent3A(t *testing.T) {
	// Test: restarts, many clients (3A) ...
	GenericTest(t, "3A", 5, false, true, false, -1)
}

func TestPersistConcurrentUnreliable3A(t *testing.T) {
	// Test: unreliable net, restarts, many clients (3A) ...
	GenericTest(t, "3A", 5, true, true, false, -1)
}

func TestPersistPartition3A(t *testing.T) {
	// Test: restarts, partitions, many clients (3A) ...
	GenericTest(t, "3A", 5, false, true, true, -1)
}

func TestPersistPartitionUnreliable3A(t *testing.T) {
	// Test: unreliable net, restarts, partitions, many clients (3A) ...
	GenericTest(t, "3A", 5, true, true, true, -1)
}

func TestPersistPartitionUnreliableLinearizable3A(t *testing.T) {
	// Test: unreliable net, restarts, partitions, linearizability checks (3A) ...
	GenericTestLinearizability(t, "3A", 15, 7, true, true, true, -1)
}

//
// if one server falls behind, then rejoins, does it
// recover by using the InstallSnapshot RPC?
// also checks that majority discards committed log entries
// even if minority doesn't respond.
//
func TestSnapshotRPC3B(t *testing.T) {
	const nservers = 3
	maxraftstate := 1000
	cfg := make_config(t, nservers, false, maxraftstate)
	defer cfg.cleanup()

	ck := cfg.makeClient(cfg.All())

	cfg.begin("Test: InstallSnapshot RPC (3B)")

	Put(cfg, ck, "a", "A")
	check(cfg, t, ck, "a", "A")

	// a bunch of puts into the majority partition.
	cfg.partition([]int{0, 1}, []int{2})
	{
		ck1 := cfg.makeClient([]int{0, 1})
		for i := 0; i < 50; i++ {
			Put(cfg, ck1, strconv.Itoa(i), strconv.Itoa(i))
		}
		time.Sleep(electionTimeout)
		Put(cfg, ck1, "b", "B")
	}

	// check that the majority partition has thrown away
	// most of its log entries.
	if cfg.LogSize() > 2*maxraftstate {
		t.Fatalf("logs were not trimmed (%v > 2*%v)", cfg.LogSize(), maxraftstate)
	}

	// now make group that requires participation of
	// lagging server, so that it has to catch up.
	cfg.partition([]int{0, 2}, []int{1})
	{
		ck1 := cfg.makeClient([]int{0, 2})
		Put(cfg, ck1, "c", "C")
		Put(cfg, ck1, "d", "D")
		check(cfg, t, ck1, "a", "A")
		check(cfg, t, ck1, "b", "B")
		check(cfg, t, ck1, "1", "1")
		check(cfg, t, ck1, "49", "49")
	}

	// now everybody
	cfg.partition([]int{0, 1, 2}, []int{})

	Put(cfg, ck, "e", "E")
	check(cfg, t, ck, "c", "C")
	check(cfg, t, ck, "e", "E")
	check(cfg, t, ck, "1", "1")

	cfg.end()
}

// are the snapshots not too huge? 500 bytes is a generous bound for the
// operations we're doing here.
func TestSnapshotSize3B(t *testing.T) {
	const nservers = 3
	maxraftstate := 1000
	maxsnapshotstate := 500
	cfg := make_config(t, nservers, false, maxraftstate)
	defer cfg.cleanup()

	ck := cfg.makeClient(cfg.All())

	cfg.begin("Test: snapshot size is reasonable (3B)")

	for i := 0; i < 200; i++ {
		Put(cfg, ck, "x", "0")
		check(cfg, t, ck, "x", "0")
		Put(cfg, ck, "x", "1")
		check(cfg, t, ck, "x", "1")
	}

	// check that servers have thrown away most of their log entries
	if cfg.LogSize() > 2*maxraftstate {
		t.Fatalf("logs were not trimmed (%v > 2*%v)", cfg.LogSize(), maxraftstate)
	}

	// check that the snapshots are not unreasonably large
	if cfg.SnapshotSize() > maxsnapshotstate {
		t.Fatalf("snapshot too large (%v > %v)", cfg.SnapshotSize(), maxsnapshotstate)
	}

	cfg.end()
}

func TestSnapshotRecover3B(t *testing.T) {
	// Test: restarts, snapshots, one client (3B) ...
	GenericTest(t, "3B", 1, false, true, false, 1000)
}

func TestSnapshotRecoverManyClients3B(t *testing.T) {
	// Test: restarts, snapshots, many clients (3B) ...
	GenericTest(t, "3B", 20, false, true, false, 1000)
}

func TestSnapshotUnreliable3B(t *testing.T) {
	// Test: unreliable net, snapshots, many clients (3B) ...
	GenericTest(t, "3B", 5, true, false, false, 1000)
}

func TestSnapshotUnreliableRecover3B(t *testing.T) {
	// Test: unreliable net, restarts, snapshots, many clients (3B) ...
	GenericTest(t, "3B", 5, true, true, false, 1000)
}

func TestSnapshotUnreliableRecoverConcurrentPartition3B(t *testing.T) {
	// Test: unreliable net, restarts, partitions, snapshots, many clients (3B) ...
	GenericTest(t, "3B", 5, true, true, true, 1000)
}

func TestSnapshotUnreliableRecoverConcurrentPartitionLinearizable3B(t *testing.T) {
	// Test: unreliable net, restarts, partitions, snapshots, linearizability checks (3B) ...
	GenericTestLinearizability(t, "3B", 15, 7, true, true, true, 1000)
}


================================================
FILE: src/labgob/labgob.go
================================================
package labgob

//
// trying to send non-capitalized fields over RPC produces a range of
// misbehavior, including both mysterious incorrect computation and
// outright crashes. so this wrapper around Go's encoding/gob warns
// about non-capitalized field names.
//

import "encoding/gob"
import "io"
import "reflect"
import "fmt"
import "sync"
import "unicode"
import "unicode/utf8"

var mu sync.Mutex
var errorCount int // for TestCapital
var checked map[reflect.Type]bool

type LabEncoder struct {
	gob *gob.Encoder
}

func NewEncoder(w io.Writer) *LabEncoder {
	enc := &LabEncoder{}
	enc.gob = gob.NewEncoder(w)
	return enc
}

func (enc *LabEncoder) Encode(e interface{}) error {
	checkValue(e)
	return enc.gob.Encode(e)
}

func (enc *LabEncoder) EncodeValue(value reflect.Value) error {
	checkValue(value.Interface())
	return enc.gob.EncodeValue(value)
}

type LabDecoder struct {
	gob *gob.Decoder
}

func NewDecoder(r io.Reader) *LabDecoder {
	dec := &LabDecoder{}
	dec.gob = gob.NewDecoder(r)
	return dec
}

func (dec *LabDecoder) Decode(e interface{}) error {
	checkValue(e)
	checkDefault(e)
	return dec.gob.Decode(e)
}

func Register(value interface{}) {
	checkValue(value)
	gob.Register(value)
}

func RegisterName(name string, value interface{}) {
	checkValue(value)
	gob.RegisterName(name, value)
}

func checkValue(value interface{}) {
	checkType(reflect.TypeOf(value))
}

func checkType(t reflect.Type) {
	k := t.Kind()

	mu.Lock()
	// only complain once, and avoid recursion.
	if checked == nil {
		checked = map[reflect.Type]bool{}
	}
	if checked[t] {
		mu.Unlock()
		return
	}
	checked[t] = true
	mu.Unlock()

	switch k {
	case reflect.Struct:
		for i := 0; i < t.NumField(); i++ {
			f := t.Field(i)
			rune, _ := utf8.DecodeRuneInString(f.Name)
			if unicode.IsUpper(rune) == false {
				// ta da
				fmt.Printf("labgob error: lower-case field %v of %v in RPC or persist/snapshot will break your Raft\n",
					f.Name, t.Name())
				mu.Lock()
				errorCount += 1
				mu.Unlock()
			}
			checkType(f.Type)
		}
		return
	case reflect.Slice, reflect.Array, reflect.Ptr:
		checkType(t.Elem())
		return
	case reflect.Map:
		checkType(t.Elem())
		checkType(t.Key())
		return
	default:
		return
	}
}

//
// warn if the value contains non-default values,
// as it would if one sent an RPC but the reply
// struct was already modified. if the RPC reply
// contains default values, GOB won't overwrite
// the non-default value.
//
func checkDefault(value interface{}) {
	if value == nil {
		return
	}
	checkDefault1(reflect.ValueOf(value), 1, "")
}

func checkDefault1(value reflect.Value, depth int, name string) {
	if depth > 3 {
		return
	}

	t := value.Type()
	k := t.Kind()

	switch k {
	case reflect.Struct:
		for i := 0; i < t.NumField(); i++ {
			vv := value.Field(i)
			name1 := t.Field(i).Name
			if name != "" {
				name1 = name + "." + name1
			}
			checkDefault1(vv, depth+1, name1)
		}
		return
	case reflect.Ptr:
		if value.IsNil() {
			return
		}
		checkDefault1(value.Elem(), depth+1, name)
		return
	case reflect.Bool,
		reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
		reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
		reflect.Uintptr, reflect.Float32, reflect.Float64,
		reflect.String:
		if reflect.DeepEqual(reflect.Zero(t).Interface(), value.Interface()) == false {
			mu.Lock()
			if errorCount < 1 {
				what := name
				if what == "" {
					what = t.Name()
				}
				// this warning typically arises if code re-uses the same RPC reply
				// variable for multiple RPC calls, or if code restores persisted
				// state into variable that already have non-default values.
				fmt.Printf("labgob warning: Decoding into a non-default variable/field %v may not work\n",
					what)
			}
			errorCount += 1
			mu.Unlock()
		}
		return
	}
}


================================================
FILE: src/labgob/test_test.go
================================================
package labgob

import "testing"

import "bytes"

type T1 struct {
	T1int0    int
	T1int1    int
	T1string0 string
	T1string1 string
}

type T2 struct {
	T2slice []T1
	T2map   map[int]*T1
	T2t3    interface{}
}

type T3 struct {
	T3int999 int
}

//
// test that we didn't break GOB.
//
func TestGOB(t *testing.T) {
	e0 := errorCount

	w := new(bytes.Buffer)

	Register(T3{})

	{
		x0 := 0
		x1 := 1
		t1 := T1{}
		t1.T1int1 = 1
		t1.T1string1 = "6.824"
		t2 := T2{}
		t2.T2slice = []T1{T1{}, t1}
		t2.T2map = map[int]*T1{}
		t2.T2map[99] = &T1{1, 2, "x", "y"}
		t2.T2t3 = T3{999}

		e := NewEncoder(w)
		e.Encode(x0)
		e.Encode(x1)
		e.Encode(t1)
		e.Encode(t2)
	}
	data := w.Bytes()

	{
		var x0 int
		var x1 int
		var t1 T1
		var t2 T2

		r := bytes.NewBuffer(data)
		d := NewDecoder(r)
		if d.Decode(&x0) != nil ||
			d.Decode(&x1) != nil ||
			d.Decode(&t1) != nil ||
			d.Decode(&t2) != nil {
			t.Fatalf("Decode failed")
		}

		if x0 != 0 {
			t.Fatalf("wrong x0 %v\n", x0)
		}
		if x1 != 1 {
			t.Fatalf("wrong x1 %v\n", x1)
		}
		if t1.T1int0 != 0 {
			t.Fatalf("wrong t1.T1int0 %v\n", t1.T1int0)
		}
		if t1.T1int1 != 1 {
			t.Fatalf("wrong t1.T1int1 %v\n", t1.T1int1)
		}
		if t1.T1string0 != "" {
			t.Fatalf("wrong t1.T1string0 %v\n", t1.T1string0)
		}
		if t1.T1string1 != "6.824" {
			t.Fatalf("wrong t1.T1string1 %v\n", t1.T1string1)
		}
		if len(t2.T2slice) != 2 {
			t.Fatalf("wrong t2.T2slice len %v\n", len(t2.T2slice))
		}
		if t2.T2slice[1].T1int1 != 1 {
			t.Fatalf("wrong slice value\n")
		}
		if len(t2.T2map) != 1 {
			t.Fatalf("wrong t2.T2map len %v\n", len(t2.T2map))
		}
		if t2.T2map[99].T1string1 != "y" {
			t.Fatalf("wrong map value\n")
		}
		t3 := (t2.T2t3).(T3)
		if t3.T3int999 != 999 {
			t.Fatalf("wrong t2.T2t3.T3int999\n")
		}
	}

	if errorCount != e0 {
		t.Fatalf("there were errors, but should not have been")
	}
}

type T4 struct {
	Yes int
	no  int
}

//
// make sure we check capitalization
// labgob prints one warning during this test.
//
func TestCapital(t *testing.T) {
	e0 := errorCount

	v := []map[*T4]int{}

	w := new(bytes.Buffer)
	e := NewEncoder(w)
	e.Encode(v)
	data := w.Bytes()

	var v1 []map[T4]int
	r := bytes.NewBuffer(data)
	d := NewDecoder(r)
	d.Decode(&v1)

	if errorCount != e0+1 {
		t.Fatalf("failed to warn about lower-case field")
	}
}

//
// check that we warn when someone sends a default value over
// RPC but the target into which we're decoding holds a non-default
// value, which GOB seems not to overwrite as you'd expect.
//
// labgob does not print a warning.
//
func TestDefault(t *testing.T) {
	e0 := errorCount

	type DD struct {
		X int
	}

	// send a default value...
	dd1 := DD{}

	w := new(bytes.Buffer)
	e := NewEncoder(w)
	e.Encode(dd1)
	data := w.Bytes()

	// and receive it into memory that already
	// holds non-default values.
	reply := DD{99}

	r := bytes.NewBuffer(data)
	d := NewDecoder(r)
	d.Decode(&reply)

	if errorCount != e0+1 {
		t.Fatalf("failed to warn about decoding into non-default value")
	}
}


================================================
FILE: src/labrpc/labrpc.go
================================================
package labrpc

//
// channel-based RPC, for 824 labs.
//
// simulates a network that can lose requests, lose replies,
// delay messages, and entirely disconnect particular hosts.
//
// we will use the original labrpc.go to test your code for grading.
// so, while you can modify this code to help you debug, please
// test against the original before submitting.
//
// adapted from Go net/rpc/server.go.
//
// sends labgob-encoded values to ensure that RPCs
// don't include references to program objects.
//
// net := MakeNetwork() -- holds network, clients, servers.
// end := net.MakeEnd(endname) -- create a client end-point, to talk to one server.
// net.AddServer(servername, server) -- adds a named server to network.
// net.DeleteServer(servername) -- eliminate the named server.
// net.Connect(endname, servername) -- connect a client to a server.
// net.Enable(endname, enabled) -- enable/disable a client.
// net.Reliable(bool) -- false means drop/delay messages
//
// end.Call("Raft.AppendEntries", &args, &reply) -- send an RPC, wait for reply.
// the "Raft" is the name of the server struct to be called.
// the "AppendEntries" is the name of the method to be called.
// Call() returns true to indicate that the server executed the request
// and the reply is valid.
// Call() returns false if the network lost the request or reply
// or the server is down.
// It is OK to have multiple Call()s in progress at the same time on the
// same ClientEnd.
// Concurrent calls to Call() may be delivered to the server out of order,
// since the network may re-order messages.
// Call() is guaranteed to return (perhaps after a delay) *except* if the
// handler function on the server side does not return.
// the server RPC handler function must declare its args and reply arguments
// as pointers, so that their types exactly match the types of the arguments
// to Call().
//
// srv := MakeServer()
// srv.AddService(svc) -- a server can have multiple services, e.g. Raft and k/v
//   pass srv to net.AddServer()
//
// svc := MakeService(receiverObject) -- obj's methods will handle RPCs
//   much like Go's rpcs.Register()
//   pass svc to srv.AddService()
//

import "labgob"
import "bytes"
import "reflect"
import "sync"
import "log"
import "strings"
import "math/rand"
import "time"
import "sync/atomic"

type reqMsg struct {
	endname  interface{} // name of sending ClientEnd
	svcMeth  string      // e.g. "Raft.AppendEntries"
	argsType reflect.Type
	args     []byte
	replyCh  chan replyMsg
}

type replyMsg struct {
	ok    bool
	reply []byte
}

type ClientEnd struct {
	endname interface{}   // this end-point's name
	ch      chan reqMsg   // copy of Network.endCh
	done    chan struct{} // closed when Network is cleaned up
}

// send an RPC, wait for the reply.
// the return value indicates success; false means that
// no reply was received from the server.
func (e *ClientEnd) Call(svcMeth string, args interface{}, reply interface{}) bool {
	req := reqMsg{}
	req.endname = e.endname
	req.svcMeth = svcMeth
	req.argsType = reflect.TypeOf(args)
	req.replyCh = make(chan replyMsg)

	qb := new(bytes.Buffer)
	qe := labgob.NewEncoder(qb)
	qe.Encode(args)
	req.args = qb.Bytes()

	select {
	case e.ch <- req:
		// ok
	case <-e.done:
		return false
	}

	rep := <-req.replyCh
	if rep.ok {
		rb := bytes.NewBuffer(rep.reply)
		rd := labgob.NewDecoder(rb)
		if err := rd.Decode(reply); err != nil {
			log.Fatalf("ClientEnd.Call(): decode reply: %v\n", err)
		}
		return true
	} else {
		return false
	}
}

type Network struct {
	mu             sync.Mutex
	reliable       bool
	longDelays     bool                        // pause a long time on send on disabled connection
	longReordering bool                        // sometimes delay replies a long time
	ends           map[interface{}]*ClientEnd  // ends, by name
	enabled        map[interface{}]bool        // by end name
	servers        map[interface{}]*Server     // servers, by name
	connections    map[interface{}]interface{} // endname -> servername
	endCh          chan reqMsg
	done           chan struct{} // closed when Network is cleaned up
	count          int32         // total RPC count, for statistics
}

func MakeNetwork() *Network {
	rn := &Network{}
	rn.reliable = true
	rn.ends = map[interface{}]*ClientEnd{}
	rn.enabled = map[interface{}]bool{}
	rn.servers = map[interface{}]*Server{}
	rn.connections = map[interface{}](interface{}){}
	rn.endCh = make(chan reqMsg)
	rn.done = make(chan struct{})

	// single goroutine to handle all ClientEnd.Call()s
	go func() {
		for {
			select {
			case xreq := <-rn.endCh:
				atomic.AddInt32(&rn.count, 1)
				go rn.ProcessReq(xreq)
			case <-rn.done:
				return
			}
		}
	}()

	return rn
}

func (rn *Network) Cleanup() {
	close(rn.done)
}

func (rn *Network) Reliable(yes bool) {
	rn.mu.Lock()
	defer rn.mu.Unlock()

	rn.reliable = yes
}

func (rn *Network) LongReordering(yes bool) {
	rn.mu.Lock()
	defer rn.mu.Unlock()

	rn.longReordering = yes
}

func (rn *Network) LongDelays(yes bool) {
	rn.mu.Lock()
	defer rn.mu.Unlock()

	rn.longDelays = yes
}

func (rn *Network) ReadEndnameInfo(endname interface{}) (enabled bool,
	servername interface{}, server *Server, reliable bool, longreordering bool,
) {
	rn.mu.Lock()
	defer rn.mu.Unlock()

	enabled = rn.enabled[endname]
	servername = rn.connections[endname]
	if servername != nil {
		server = rn.servers[servername]
	}
	reliable = rn.reliable
	longreordering = rn.longReordering
	return
}

func (rn *Network) IsServerDead(endname interface{}, servername interface{}, server *Server) bool {
	rn.mu.Lock()
	defer rn.mu.Unlock()

	if rn.enabled[endname] == false || rn.servers[servername] != server {
		return true
	}
	return false
}

func (rn *Network) ProcessReq(req reqMsg) {
	enabled, servername, server, reliable, longreordering := rn.ReadEndnameInfo(req.endname)

	if enabled && servername != nil && server != nil {
		if reliable == false {
			// short delay
			ms := (rand.Int() % 27)
			time.Sleep(time.Duration(ms) * time.Millisecond)
		}

		if reliable == false && (rand.Int()%1000) < 100 {
			// drop the request, return as if timeout
			req.replyCh <- replyMsg{false, nil}
			return
		}

		// execute the request (call the RPC handler).
		// in a separate thread so that we can periodically check
		// if the server has been killed and the RPC should get a
		// failure reply.
		ech := make(chan replyMsg)
		go func() {
			r := server.dispatch(req)
			ech <- r
		}()

		// wait for handler to return,
		// but stop waiting if DeleteServer() has been called,
		// and return an error.
		var reply replyMsg
		replyOK := false
		serverDead := false
		for replyOK == false && serverDead == false {
			select {
			case reply = <-ech:
				replyOK = true
			case <-time.After(100 * time.Millisecond):
				serverDead = rn.IsServerDead(req.endname, servername, server)
				if serverDead {
					go func() {
						<-ech // drain channel to let the goroutine created earlier terminate
					}()
				}
			}
		}

		// do not reply if DeleteServer() has been called, i.e.
		// the server has been killed. this is needed to avoid
		// situation in which a client gets a positive reply
		// to an Append, but the server persisted the update
		// into the old Persister. config.go is careful to call
		// DeleteServer() before superseding the Persister.
		serverDead = rn.IsServerDead(req.endname, servername, server)

		if replyOK == false || serverDead == true {
			// server was killed while we were waiting; return error.
			req.replyCh <- replyMsg{false, nil}
		} else if reliable == false && (rand.Int()%1000) < 100 {
			// drop the reply, return as if timeout
			req.replyCh <- replyMsg{false, nil}
		} else if longreordering == true && rand.Intn(900) < 600 {
			// delay the response for a while
			ms := 200 + rand.Intn(1+rand.Intn(2000))
			// Russ points out that this timer arrangement will decrease
			// the number of goroutines, so that the race
			// detector is less likely to get upset.
			time.AfterFunc(time.Duration(ms)*time.Millisecond, func() {
				req.replyCh <- reply
			})
		} else {
			req.replyCh <- reply
		}
	} else {
		// simulate no reply and eventual timeout.
		ms := 0
		if rn.longDelays {
			// let Raft tests check that leader doesn't send
			// RPCs synchronously.
			ms = (rand.Int() % 7000)
		} else {
			// many kv tests require the client to try each
			// server in fairly rapid succession.
			ms = (rand.Int() % 100)
		}
		time.AfterFunc(time.Duration(ms)*time.Millisecond, func() {
			req.replyCh <- replyMsg{false, nil}
		})
	}

}

// create a client end-point.
// start the thread that listens and delivers.
func (rn *Network) MakeEnd(endname interface{}) *ClientEnd {
	rn.mu.Lock()
	defer rn.mu.Unlock()

	if _, ok := rn.ends[endname]; ok {
		log.Fatalf("MakeEnd: %v already exists\n", endname)
	}

	e := &ClientEnd{}
	e.endname = endname
	e.ch = rn.endCh
	e.done = rn.done
	rn.ends[endname] = e
	rn.enabled[endname] = false
	rn.connections[endname] = nil

	return e
}

func (rn *Network) AddServer(servername interface{}, rs *Server) {
	rn.mu.Lock()
	defer rn.mu.Unlock()

	rn.servers[servername] = rs
}

func (rn *Network) DeleteServer(servername interface{}) {
	rn.mu.Lock()
	defer rn.mu.Unlock()

	rn.servers[servername] = nil
}

// connect a ClientEnd to a server.
// a ClientEnd can only be connected once in its lifetime.
func (rn *Network) Connect(endname interface{}, servername interface{}) {
	rn.mu.Lock()
	defer rn.mu.Unlock()

	rn.connections[endname] = servername
}

// enable/disable a ClientEnd.
func (rn *Network) Enable(endname interface{}, enabled bool) {
	rn.mu.Lock()
	defer rn.mu.Unlock()

	rn.enabled[endname] = enabled
}

// get a server's count of incoming RPCs.
func (rn *Network) GetCount(servername interface{}) int {
	rn.mu.Lock()
	defer rn.mu.Unlock()

	svr := rn.servers[servername]
	return svr.GetCount()
}

func (rn *Network) GetTotalCount() int {
	x := atomic.LoadInt32(&rn.count)
	return int(x)
}

//
// a server is a collection of services, all sharing
// the same rpc dispatcher. so that e.g. both a Raft
// and a k/v server can listen to the same rpc endpoint.
//
type Server struct {
	mu       sync.Mutex
	services map[string]*Service
	count    int // incoming RPCs
}

func MakeServer() *Server {
	rs := &Server{}
	rs.services = map[string]*Service{}
	return rs
}

func (rs *Server) AddService(svc *Service) {
	rs.mu.Lock()
	defer rs.mu.Unlock()
	rs.services[svc.name] = svc
}

func (rs *Server) dispatch(req reqMsg) replyMsg {
	rs.mu.Lock()

	rs.count += 1

	// split Raft.AppendEntries into service and method
	dot := strings.LastIndex(req.svcMeth, ".")
	serviceName := req.svcMeth[:dot]
	methodName := req.svcMeth[dot+1:]

	service, ok := rs.services[serviceName]

	rs.mu.Unlock()

	if ok {
		return service.dispatch(methodName, req)
	} else {
		choices := []string{}
		for k, _ := range rs.services {
			choices = append(choices, k)
		}
		log.Fatalf("labrpc.Server.dispatch(): unknown service %v in %v.%v; expecting one of %v\n",
			serviceName, serviceName, methodName, choices)
		return replyMsg{false, nil}
	}
}

func (rs *Server) GetCount() int {
	rs.mu.Lock()
	defer rs.mu.Unlock()
	return rs.count
}

// an object with methods that can be called via RPC.
// a single server may have more than one Service.
type Service struct {
	name    string
	rcvr    reflect.Value
	typ     reflect.Type
	methods map[string]reflect.Method
}

func MakeService(rcvr interface{}) *Service {
	svc := &Service{}
	svc.typ = reflect.TypeOf(rcvr)
	svc.rcvr = reflect.ValueOf(rcvr)
	svc.name = reflect.Indirect(svc.rcvr).Type().Name()
	svc.methods = map[string]reflect.Method{}

	for m := 0; m < svc.typ.NumMethod(); m++ {
		method := svc.typ.Method(m)
		mtype := method.Type
		mname := method.Name

		//fmt.Printf("%v pp %v ni %v 1k %v 2k %v no %v\n",
		//	mname, method.PkgPath, mtype.NumIn(), mtype.In(1).Kind(), mtype.In(2).Kind(), mtype.NumOut())

		if method.PkgPath != "" || // capitalized?
			mtype.NumIn() != 3 ||
			//mtype.In(1).Kind() != reflect.Ptr ||
			mtype.In(2).Kind() != reflect.Ptr ||
			mtype.NumOut() != 0 {
			// the method is not suitable for a handler
			//fmt.Printf("bad method: %v\n", mname)
		} else {
			// the method looks like a handler
			svc.methods[mname] = method
		}
	}

	return svc
}

func (svc *Service) dispatch(methname string, req reqMsg) replyMsg {
	if method, ok := svc.methods[methname]; ok {
		// prepare space into which to read the argument.
		// the Value's type will be a pointer to req.argsType.
		args := reflect.New(req.argsType)

		// decode the argument.
		ab := bytes.NewBuffer(req.args)
		ad := labgob.NewDecoder(ab)
		ad.Decode(args.Interface())

		// allocate space for the reply.
		replyType := method.Type.In(2)
		replyType = replyType.Elem()
		replyv := reflect.New(replyType)

		// call the method.
		function := method.Func
		function.Call([]reflect.Value{svc.rcvr, args.Elem(), replyv})

		// encode the reply.
		rb := new(bytes.Buffer)
		re := labgob.NewEncoder(rb)
		re.EncodeValue(replyv)

		return replyMsg{true, rb.Bytes()}
	} else {
		choices := []string{}
		for k, _ := range svc.methods {
			choices = append(choices, k)
		}
		log.Fatalf("labrpc.Service.dispatch(): unknown method %v in %v; expecting one of %v\n",
			methname, req.svcMeth, choices)
		return replyMsg{false, nil}
	}
}


================================================
FILE: src/labrpc/test_test.go
================================================
package labrpc

import "testing"
import "strconv"
import "sync"
import "runtime"
import "time"
import "fmt"

type JunkArgs struct {
	X int
}
type JunkReply struct {
	X string
}

type JunkServer struct {
	mu   sync.Mutex
	log1 []string
	log2 []int
}

func (js *JunkServer) Handler1(args string, reply *int) {
	js.mu.Lock()
	defer js.mu.Unlock()
	js.log1 = append(js.log1, args)
	*reply, _ = strconv.Atoi(args)
}

func (js *JunkServer) Handler2(args int, reply *string) {
	js.mu.Lock()
	defer js.mu.Unlock()
	js.log2 = append(js.log2, args)
	*reply = "handler2-" + strconv.Itoa(args)
}

func (js *JunkServer) Handler3(args int, reply *int) {
	js.mu.Lock()
	defer js.mu.Unlock()
	time.Sleep(20 * time.Second)
	*reply = -args
}

// args is a pointer
func (js *JunkServer) Handler4(args *JunkArgs, reply *JunkReply) {
	reply.X = "pointer"
}

// args is a not pointer
func (js *JunkServer) Handler5(args JunkArgs, reply *JunkReply) {
	reply.X = "no pointer"
}

func TestBasic(t *testing.T) {
	runtime.GOMAXPROCS(4)

	rn := MakeNetwork()
	defer rn.Cleanup()

	e := rn.MakeEnd("end1-99")

	js := &JunkServer{}
	svc := MakeService(js)

	rs := MakeServer()
	rs.AddService(svc)
	rn.AddServer("server99", rs)

	rn.Connect("end1-99", "server99")
	rn.Enable("end1-99", true)

	{
		reply := ""
		e.Call("JunkServer.Handler2", 111, &reply)
		if reply != "handler2-111" {
			t.Fatalf("wrong reply from Handler2")
		}
	}

	{
		reply := 0
		e.Call("JunkServer.Handler1", "9099", &reply)
		if reply != 9099 {
			t.Fatalf("wrong reply from Handler1")
		}
	}
}

func TestTypes(t *testing.T) {
	runtime.GOMAXPROCS(4)

	rn := MakeNetwork()
	defer rn.Cleanup()

	e := rn.MakeEnd("end1-99")

	js := &JunkServer{}
	svc := MakeService(js)

	rs := MakeServer()
	rs.AddService(svc)
	rn.AddServer("server99", rs)

	rn.Connect("end1-99", "server99")
	rn.Enable("end1-99", true)

	{
		var args JunkArgs
		var reply JunkReply
		// args must match type (pointer or not) of handler.
		e.Call("JunkServer.Handler4", &args, &reply)
		if reply.X != "pointer" {
			t.Fatalf("wrong reply from Handler4")
		}
	}

	{
		var args JunkArgs
		var reply JunkReply
		// args must match type (pointer or not) of handler.
		e.Call("JunkServer.Handler5", args, &reply)
		if reply.X != "no pointer" {
			t.Fatalf("wrong reply from Handler5")
		}
	}
}

//
// does net.Enable(endname, false) really disconnect a client?
//
func TestDisconnect(t *testing.T) {
	runtime.GOMAXPROCS(4)

	rn := MakeNetwork()
	defer rn.Cleanup()

	e := rn.MakeEnd("end1-99")

	js := &JunkServer{}
	svc := MakeService(js)

	rs := MakeServer()
	rs.AddService(svc)
	rn.AddServer("server99", rs)

	rn.Connect("end1-99", "server99")

	{
		reply := ""
		e.Call("JunkServer.Handler2", 111, &reply)
		if reply != "" {
			t.Fatalf("unexpected reply from Handler2")
		}
	}

	rn.Enable("end1-99", true)

	{
		reply := 0
		e.Call("JunkServer.Handler1", "9099", &reply)
		if reply != 9099 {
			t.Fatalf("wrong reply from Handler1")
		}
	}
}

//
// test net.GetCount()
//
func TestCounts(t *testing.T) {
	runtime.GOMAXPROCS(4)

	rn := MakeNetwork()
	defer rn.Cleanup()

	e := rn.MakeEnd("end1-99")

	js := &JunkServer{}
	svc := MakeService(js)

	rs := MakeServer()
	rs.AddService(svc)
	rn.AddServer(99, rs)

	rn.Connect("end1-99", 99)
	rn.Enable("end1-99", true)

	for i := 0; i < 17; i++ {
		reply := ""
		e.Call("JunkServer.Handler2", i, &reply)
		wanted := "handler2-" + strconv.Itoa(i)
		if reply != wanted {
			t.Fatalf("wrong reply %v from Handler1, expecting %v", reply, wanted)
		}
	}

	n := rn.GetCount(99)
	if n != 17 {
		t.Fatalf("wrong GetCount() %v, expected 17\n", n)
	}
}

//
// test RPCs from concurrent ClientEnds
//
func TestConcurrentMany(t *testing.T) {
	runtime.GOMAXPROCS(4)

	rn := MakeNetwork()
	defer rn.Cleanup()

	js := &JunkServer{}
	svc := MakeService(js)

	rs := MakeServer()
	rs.AddService(svc)
	rn.AddServer(1000, rs)

	ch := make(chan int)

	nclients := 20
	nrpcs := 10
	for ii := 0; ii < nclients; ii++ {
		go func(i int) {
			n := 0
			defer func() { ch <- n }()

			e := rn.MakeEnd(i)
			rn.Connect(i, 1000)
			rn.Enable(i, true)

			for j := 0; j < nrpcs; j++ {
				arg := i*100 + j
				reply := ""
				e.Call("JunkServer.Handler2", arg, &reply)
				wanted := "handler2-" + strconv.Itoa(arg)
				if reply != wanted {
					t.Fatalf("wrong reply %v from Handler1, expecting %v", reply, wanted)
				}
				n += 1
			}
		}(ii)
	}

	total := 0
	for ii := 0; ii < nclients; ii++ {
		x := <-ch
		total += x
	}

	if total != nclients*nrpcs {
		t.Fatalf("wrong number of RPCs completed, got %v, expected %v", total, nclients*nrpcs)
	}

	n := rn.GetCount(1000)
	if n != total {
		t.Fatalf("wrong GetCount() %v, expected %v\n", n, total)
	}
}

//
// test unreliable
//
func TestUnreliable(t *testing.T) {
	runtime.GOMAXPROCS(4)

	rn := MakeNetwork()
	defer rn.Cleanup()
	rn.Reliable(false)

	js := &JunkServer{}
	svc := MakeService(js)

	rs := MakeServer()
	rs.AddService(svc)
	rn.AddServer(1000, rs)

	ch := make(chan int)

	nclients := 300
	for ii := 0; ii < nclients; ii++ {
		go func(i int) {
			n := 0
			defer func() { ch <- n }()

			e := rn.MakeEnd(i)
			rn.Connect(i, 1000)
			rn.Enable(i, true)

			arg := i * 100
			reply := ""
			ok := e.Call("JunkServer.Handler2", arg, &reply)
			if ok {
				wanted := "handler2-" + strconv.Itoa(arg)
				if reply != wanted {
					t.Fatalf("wrong reply %v from Handler1, expecting %v", reply, wanted)
				}
				n += 1
			}
		}(ii)
	}

	total := 0
	for ii := 0; ii < nclients; ii++ {
		x := <-ch
		total += x
	}

	if total == nclients || total == 0 {
		t.Fatalf("all RPCs succeeded despite unreliable")
	}
}

//
// test concurrent RPCs from a single ClientEnd
//
func TestConcurrentOne(t *testing.T) {
	runtime.GOMAXPROCS(4)

	rn := MakeNetwork()
	defer rn.Cleanup()

	js := &JunkServer{}
	svc := MakeService(js)

	rs := MakeServer()
	rs.AddService(svc)
	rn.AddServer(1000, rs)

	e := rn.MakeEnd("c")
	rn.Connect("c", 1000)
	rn.Enable("c", true)

	ch := make(chan int)

	nrpcs := 20
	for ii := 0; ii < nrpcs; ii++ {
		go func(i int) {
			n := 0
			defer func() { ch <- n }()

			arg := 100 + i
			reply := ""
			e.Call("JunkServer.Handler2", arg, &reply)
			wanted := "handler2-" + strconv.Itoa(arg)
			if reply != wanted {
				t.Fatalf("wrong reply %v from Handler2, expecting %v", reply, wanted)
			}
			n += 1
		}(ii)
	}

	total := 0
	for ii := 0; ii < nrpcs; ii++ {
		x := <-ch
		total += x
	}

	if total != nrpcs {
		t.Fatalf("wrong number of RPCs completed, got %v, expected %v", total, nrpcs)
	}

	js.mu.Lock()
	defer js.mu.Unlock()
	if len(js.log2) != nrpcs {
		t.Fatalf("wrong number of RPCs delivered")
	}

	n := rn.GetCount(1000)
	if n != total {
		t.Fatalf("wrong GetCount() %v, expected %v\n", n, total)
	}
}

//
// regression: an RPC that's delayed during Enabled=false
// should not delay subsequent RPCs (e.g. after Enabled=true).
//
func TestRegression1(t *testing.T) {
	runtime.GOMAXPROCS(4)

	rn := MakeNetwork()
	defer rn.Cleanup()

	js := &JunkServer{}
	svc := MakeService(js)

	rs := MakeServer()
	rs.AddService(svc)
	rn.AddServer(1000, rs)

	e := rn.MakeEnd("c")
	rn.Connect("c", 1000)

	// start some RPCs while the ClientEnd is disabled.
	// they'll be delayed.
	rn.Enable("c", false)
	ch := make(chan bool)
	nrpcs := 20
	for ii := 0; ii < nrpcs; ii++ {
		go func(i int) {
			ok := false
			defer func() { ch <- ok }()

			arg := 100 + i
			reply := ""
			// this call ought to return false.
			e.Call("JunkServer.Handler2", arg, &reply)
			ok = true
		}(ii)
	}

	time.Sleep(100 * time.Millisecond)

	// now enable the ClientEnd and check that an RPC completes quickly.
	t0 := time.Now()
	rn.Enable("c", true)
	{
		arg := 99
		reply := ""
		e.Call("JunkServer.Handler2", arg, &reply)
		wanted := "handler2-" + strconv.Itoa(arg)
		if reply != wanted {
			t.Fatalf("wrong reply %v from Handler2, expecting %v", reply, wanted)
		}
	}
	dur := time.Since(t0).Seconds()

	if dur > 0.03 {
		t.Fatalf("RPC took too long (%v) after Enable", dur)
	}

	for ii := 0; ii < nrpcs; ii++ {
		<-ch
	}

	js.mu.Lock()
	defer js.mu.Unlock()
	if len(js.log2) != 1 {
		t.Fatalf("wrong number (%v) of RPCs delivered, expected 1", len(js.log2))
	}

	n := rn.GetCount(1000)
	if n != 1 {
		t.Fatalf("wrong GetCount() %v, expected %v\n", n, 1)
	}
}

//
// if an RPC is stuck in a server, and the server
// is killed with DeleteServer(), does the RPC
// get un-stuck?
//
func TestKilled(t *testing.T) {
	runtime.GOMAXPROCS(4)

	rn := MakeNetwork()
	defer rn.Cleanup()

	e := rn.MakeEnd("end1-99")

	js := &JunkServer{}
	svc := MakeService(js)

	rs := MakeServer()
	rs.AddService(svc)
	rn.AddServer("server99", rs)

	rn.Connect("end1-99", "server99")
	rn.Enable("end1-99", true)

	doneCh := make(chan bool)
	go func() {
		reply := 0
		ok := e.Call("JunkServer.Handler3", 99, &reply)
		doneCh <- ok
	}()

	time.Sleep(1000 * time.Millisecond)

	select {
	case <-doneCh:
		t.Fatalf("Handler3 should not have returned yet")
	case <-time.After(100 * time.Millisecond):
	}

	rn.DeleteServer("server99")

	select {
	case x := <-doneCh:
		if x != false {
			t.Fatalf("Handler3 returned successfully despite DeleteServer()")
		}
	case <-time.After(100 * time.Millisecond):
		t.Fatalf("Handler3 should return after DeleteServer()")
	}
}

func TestBenchmark(t *testing.T) {
	runtime.GOMAXPROCS(4)

	rn := MakeNetwork()
	defer rn.Cleanup()

	e := rn.MakeEnd("end1-99")

	js := &JunkServer{}
	svc := MakeService(js)

	rs := MakeServer()
	rs.AddService(svc)
	rn.AddServer("server99", rs)

	rn.Connect("end1-99", "server99")
	rn.Enable("end1-99", true)

	t0 := time.Now()
	n := 100000
	for iters := 0; iters < n; iters++ {
		reply := ""
		e.Call("JunkServer.Handler2", 111, &reply)
		if reply != "handler2-111" {
			t.Fatalf("wrong reply from Handler2")
		}
	}
	fmt.Printf("%v for %v\n", time.Since(t0), n)
	// march 2016, rtm laptop, 22 microseconds per RPC
}


================================================
FILE: src/linearizability/bitset.go
================================================
package linearizability

type bitset []uint64

// data layout:
// bits 0-63 are in data[0], the next are in data[1], etc.

func newBitset(bits uint) bitset {
	extra := uint(0)
	if bits%64 != 0 {
		extra = 1
	}
	chunks := bits/64 + extra
	return bitset(make([]uint64, chunks))
}

func (b bitset) clone() bitset {
	dataCopy := make([]uint64, len(b))
	copy(dataCopy, b)
	return bitset(dataCopy)
}

func bitsetIndex(pos uint) (uint, uint) {
	return pos / 64, pos % 64
}

func (b bitset) set(pos uint) bitset {
	major, minor := bitsetIndex(pos)
	b[major] |= (1 << minor)
	return b
}

func (b bitset) clear(pos uint) bitset {
	major, minor := bitsetIndex(pos)
	b[major] &^= (1 << minor)
	return b
}

func (b bitset) get(pos uint) bool {
	major, minor := bitsetIndex(pos)
	return b[major]&(1<<minor) != 0
}

func (b bitset) popcnt() uint {
	total := uint(0)
	for _, v := range b {
		v = (v & 0x5555555555555555) + ((v & 0xAAAAAAAAAAAAAAAA) >> 1)
		v = (v & 0x3333333333333333) + ((v & 0xCCCCCCCCCCCCCCCC) >> 2)
		v = (v & 0x0F0F0F0F0F0F0F0F) + ((v & 0xF0F0F0F0F0F0F0F0) >> 4)
		v *= 0x0101010101010101
		total += uint((v >> 56) & 0xFF)
	}
	return total
}

func (b bitset) hash() uint64 {
	hash := uint64(b.popcnt())
	for _, v := range b {
		hash ^= v
	}
	return hash
}

func (b bitset) equals(b2 bitset) bool {
	if len(b) != len(b2) {
		return false
	}
	for i := range b {
		if b[i] != b2[i] {
			return false
		}
	}
	return true
}


================================================
FILE: src/linearizability/linearizability.go
================================================
package linearizability

import (
	"sort"
	"sync/atomic"
	"time"
)

type entryKind bool

const (
	callEntry   entryKind = false
	returnEntry           = true
)

type entry struct {
	kind  entryKind
	value interface{}
	id    uint
	time  int64
}

type byTime []entry

func (a byTime) Len() int {
	return len(a)
}

func (a byTime) Swap(i, j int) {
	a[i], a[j] = a[j], a[i]
}

func (a byTime) Less(i, j int) bool {
	return a[i].time < a[j].time
}

func makeEntries(history []Operation) []entry {
	var entries []entry = nil
	id := uint(0)
	for _, elem := range history {
		entries = append(entries, entry{
			callEntry, elem.Input, id, elem.Call})
		entries = append(entries, entry{
			returnEntry, elem.Output, id, elem.Return})
		id++
	}
	sort.Sort(byTime(entries))
	return entries
}

type node struct {
	value interface{}
	match *node // call if match is nil, otherwise return
	id    uint
	next  *node
	prev  *node
}

func insertBefore(n *node, mark *node) *node {
	if mark != nil {
		beforeMark := mark.prev
		mark.prev = n
		n.next = mark
		if beforeMark != nil {
			n.prev = beforeMark
			beforeMark.next = n
		}
	}
	return n
}

func length(n *node) uint {
	l := uint(0)
	for n != nil {
		n = n.next
		l++
	}
	return l
}

func renumber(events []Event) []Event {
	var e []Event
	m := make(map[uint]uint) // renumbering
	id := uint(0)
	for _, v := range events {
		if r, ok := m[v.Id]; ok {
			e = append(e, Event{v.Kind, v.Value, r})
		} else {
			e = append(e, Event{v.Kind, v.Value, id})
			m[v.Id] = id
			id++
		}
	}
	return e
}

func convertEntries(events []Event) []entry {
	var entries []entry
	for _, elem := range events {
		kind := callEntry
		if elem.Kind == ReturnEvent {
			kind = returnEntry
		}
		entries = append(entries, entry{kind, elem.Value, elem.Id, -1})
	}
	return entries
}

func makeLinkedEntries(entries []entry) *node {
	var root *node = nil
	match := make(map[uint]*node)
	for i := len(entries) - 1; i >= 0; i-- {
		elem := entries[i]
		if elem.kind == returnEntry {
			entry := &node{value: elem.value, match: nil, id: elem.id}
			match[elem.id] = entry
			insertBefore(entry, root)
			root = entry
		} else {
			entry := &node{value: elem.value, match: match[elem.id], id: elem.id}
			insertBefore(entry, root)
			root = entry
		}
	}
	return root
}

type cacheEntry struct {
	linearized bitset
	state      interface{}
}

func cacheContains(model Model, cache map[uint64][]cacheEntry, entry cacheEntry) bool {
	for _, elem := range cache[entry.linearized.hash()] {
		if entry.linearized.equals(elem.linearized) && model.Equal(entry.state, elem.state) {
			return true
		}
	}
	return false
}

type callsEntry struct {
	entry *node
	state interface{}
}

func lift(entry *node) {
	entry.prev.next = entry.next
	entry.next.prev = entry.prev
	match := entry.match
	match.prev.next = match.next
	if match.next != nil {
		match.next.prev = match.prev
	}
}

func unlift(entry *node) {
	match := entry.match
	match.prev.next = match
	if match.next != nil {
		match.next.prev = match
	}
	entry.prev.next = entry
	entry.next.prev = entry
}

func checkSingle(model Model, subhistory *node, kill *int32) bool {
	n := length(subhistory) / 2
	linearized := newBitset(n)
	cache := make(map[uint64][]cacheEntry) // map from hash to cache entry
	var calls []callsEntry

	state := model.Init()
	headEntry := insertBefore(&node{value: nil, match: nil, id: ^uint(0)}, subhistory)
	entry := subhistory
	for headEntry.next != nil {
		if atomic.LoadInt32(kill) != 0 {
			return false
		}
		if entry.match != nil {
			matching := entry.match // the return entry
			ok, newState := model.Step(state, entry.value, matching.value)
			if ok {
				newLinearized := linearized.clone().set(entry.id)
				newCacheEntry := cacheEntry{newLinearized, newState}
				if !cacheContains(model, cache, newCacheEntry) {
					hash := newLinearized.hash()
					cache[hash] = append(cache[hash], newCacheEntry)
					calls = append(calls, callsEntry{entry, state})
					state = newState
					linearized.set(entry.id)
					lift(entry)
					entry = headEntry.next
				} else {
					entry = entry.next
				}
			} else {
				entry = entry.next
			}
		} else {
			if len(calls) == 0 {
				return false
			}
			callsTop := calls[len(calls)-1]
			entry = callsTop.entry
			state = callsTop.state
			linearized.clear(entry.id)
			calls = calls[:len(calls)-1]
			unlift(entry)
			entry = entry.next
		}
	}
	return true
}

func fillDefault(model Model) Model {
	if model.Partition == nil {
		model.Partition = NoPartition
	}
	if model.PartitionEvent == nil {
		model.PartitionEvent = NoPartitionEvent
	}
	if model.Equal == nil {
		model.Equal = ShallowEqual
	}
	return model
}

func CheckOperations(model Model, history []Operation) bool {
	return CheckOperationsTimeout(model, history, 0)
}

// timeout = 0 means no timeout
// if this operation times out, then a false positive is possible
func CheckOperationsTimeout(model Model, history []Operation, timeout time.Duration) bool {
	model = fillDefault(model)
	partitions := model.Partition(history)
	ok := true
	results := make(chan bool)
	kill := int32(0)
	for _, subhistory := range partitions {
		l := makeLinkedEntries(makeEntries(subhistory))
		go func() {
			results <- checkSingle(model, l, &kill)
		}()
	}
	var timeoutChan <-chan time.Time
	if timeout > 0 {
		timeoutChan = time.After(timeout)
	}
	count := 0
loop:
	for {
		select {
		case result := <-results:
			ok = ok && result
			if !ok {
				atomic.StoreInt32(&kill, 1)
				break loop
			}
			count++
			if count >= len(partitions) {
				break loop
			}
		case <-timeoutChan:
			break loop // if we time out, we might get a false positive
		}
	}
	return ok
}

func CheckEvents(model Model, history []Event) bool {
	return CheckEventsTimeout(model, history, 0)
}

// timeout = 0 means no timeout
// if this operation times out, then a false positive is possible
func CheckEventsTimeout(model Model, history []Event, timeout time.Duration) bool {
	model = fillDefault(model)
	partitions := model.PartitionEvent(history)
	ok := true
	results := make(chan bool)
	kill := int32(0)
	for _, subhistory := range partitions {
		l := makeLinkedEntries(convertEntries(renumber(subhistory)))
		go func() {
			results <- checkSingle(model, l, &kill)
		}()
	}
	var timeoutChan <-chan time.Time
	if timeout > 0 {
		timeoutChan = time.After(timeout)
	}
	count := 0
loop:
	for {
		select {
		case result := <-results:
			ok = ok && result
			if !ok {
				atomic.StoreInt32(&kill, 1)
				break loop
			}
			count++
			if count >= len(partitions) {
				break loop
			}
		case <-timeoutChan:
			break loop // if we time out, we might get a false positive
		}
	}
	return ok
}


================================================
FILE: src/linearizability/model.go
================================================
package linearizability

type Operation struct {
	Input  interface{}
	Call   int64 // invocation time
	Output interface{}
	Return int64 // response time
}

type EventKind bool

const (
	CallEvent   EventKind = false
	ReturnEvent EventKind = true
)

type Event struct {
	Kind  EventKind
	Value interface{}
	Id    uint
}

type Model struct {
	// Partition functions, such that a history is linearizable if an only
	// if each partition is linearizable. If you don't want to implement
	// this, you can always use the `NoPartition` functions implemented
	// below.
	Partition      func(history []Operation) [][]Operation
	PartitionEvent func(history []Event) [][]Event
	// Initial state of the system.
	Init func() interface{}
	// Step function for the system. Returns whether or not the system
	// could take this step with the given inputs and outputs and also
	// returns the new state. This should not mutate the existing state.
	Step func(state interface{}, input interface{}, output interface{}) (bool, interface{})
	// Equality on states. If you are using a simple data type for states,
	// you can use the `ShallowEqual` function implemented below.
	Equal func(state1, state2 interface{}) bool
}

func NoPartition(history []Operation) [][]Operation {
	return [][]Operation{history}
}

func NoPartitionEvent(history []Event) [][]Event {
	return [][]Event{history}
}

func ShallowEqual(state1, state2 interface{}) bool {
	return state1 == state2
}


================================================
FILE: src/linearizability/models.go
================================================
package linearizability

// kv model

type KvInput struct {
	Op uint8 // 0 => get, 1 => put, 2 => append
	Key string
	Value string
}

type KvOutput struct {
	Value string
}

func KvModel() Model {
    return Model {
        Partition: func(history []Operation) [][]Operation {
            m := make(map[string][]Operation)
            for _, v := range history {
                key := v.Input.(KvInput).Key
                m[key] = append(m[key], v)
            }
            var ret [][]Operation
            for _, v := range m {
                ret = append(ret, v)
            }
            return ret
        },
        Init: func() interface{} {
            // note: we are modeling a single key's value here;
            // we're partitioning by key, so this is okay
            return ""
        },
        Step: func(state, input, output interface{}) (bool, interface{}) {
            inp := input.(KvInput)
            out := output.(KvOutput)
            st := state.(string)
            if inp.Op == 0 {
                // get
                return out.Value == st, state
            } else if inp.Op == 1 {
                // put
                return true, inp.Value
            } else {
                // append
                return true, (st + inp.Value)
            }
        },
        Equal: ShallowEqual,
    }
}


================================================
FILE: src/main/diskvd.go
================================================
package main

//
// start a diskvd server. it's a member of some replica
// group, which has other members, and it needs to know
// how to talk to the members of the shardmaster service.
// used by ../diskv/test_test.go
//
// arguments:
//   -g groupid
//   -m masterport1 -m masterport2 ...
//   -s replicaport1 -s replicaport2 ...
//   -i my-index-in-server-port-list
//   -u unreliable
//   -d directory
//   -r restart

import "time"
import "diskv"
import "os"
import "fmt"
import "strconv"
import "runtime"

func usage() {
	fmt.Printf("Usage: diskvd -g gid -m master... -s server... -i my-index -d dir\n")
	os.Exit(1)
}

func main() {
	var gid int64 = -1     // my replica group ID
	masters := []string{}  // ports of shardmasters
	replicas := []string{} // ports of servers in my replica group
	me := -1               // my index in replicas[]
	unreliable := false
	dir := "" // store persistent data here
	restart := false

	for i := 1; i+1 < len(os.Args); i += 2 {
		a0 := os.Args[i]
		a1 := os.Args[i+1]
		if a0 == "-g" {
			gid, _ = strconv.ParseInt(a1, 10, 64)
		} else if a0 == "-m" {
			masters = append(masters, a1)
		} else if a0 == "-s" {
			replicas = append(replicas, a1)
		} else if a0 == "-i" {
			me, _ = strconv.Atoi(a1)
		} else if a0 == "-u" {
			unreliable, _ = strconv.ParseBool(a1)
		} else if a0 == "-d" {
			dir = a1
		} else if a0 == "-r" {
			restart, _ = strconv.ParseBool(a1)
		} else {
			usage()
		}
	}

	if gid < 0 || me < 0 || len(masters) < 1 || me >= len(replicas) || dir == "" {
		usage()
	}

	runtime.GOMAXPROCS(4)

	srv := diskv.StartServer(gid, masters, replicas, me, dir, restart)
	srv.Setunreliable(unreliable)

	// for safety, force quit after 10 minutes.
	time.Sleep(10 * 60 * time.Second)
	mep, _ := os.FindProcess(os.Getpid())
	mep.Kill()
}


================================================
FILE: src/main/ii.go
================================================
package main

import "os"
import "fmt"
import "mapreduce"
import "strings"
import "unicode"
import "strconv"
// The mapping function is called once for each piece of the input.
// In this framework, the key is the name of the file that is being processed,
// and the value is the file's contents. The return value should be a slice of
// key/value pairs, each represented by a mapreduce.KeyValue.
func mapF(document string, value string) (res []mapreduce.KeyValue) {
	//分割词
	words := strings.FieldsFunc(value,
		func(c rune) bool {
			return !unicode.IsLetter(c)
		})
	//建立词索引
	wordsKv := make(map[string]string)
	for _, word := range words {
		wordsKv[word] = document
	}
	//转换为输出格式
	var rst []mapreduce.KeyValue
	for key, value := range wordsKv {
		kv := mapreduce.KeyValue{
			key,
			value,
		}
		rst = append(rst, kv)
	}
	return rst
}

// The reduce function is called once for each key generated by Map, with a
// list of that key's string value (merged across all inputs). The return value
// should be a single output value for that key.
func reduceF(key string, values []string) string {
	//合并结果
	return strconv.Itoa(len(values)) + " " + strings.Join(values, ",")
}

// Can be run in 3 ways:
// 1) Sequential (e.g., go run wc.go master sequential x1.txt .. xN.txt)
// 2) Master (e.g., go run wc.go master localhost:7777 x1.txt .. xN.txt)
// 3) Worker (e.g., go run wc.go worker localhost:7777 localhost:7778 &)
func main() {
	if len(os.Args) < 4 {
		fmt.Printf("%s: see usage comments in file\n", os.Args[0])
	} else if os.Args[1] == "master" {
		var mr *mapreduce.Master
		if os.Args[2] == "sequential" {
			mr = mapreduce.Sequential("iiseq", os.Args[3:], 3, mapF, reduceF)
		} else {
			mr = mapreduce.Distributed("iiseq", os.Args[3:], 3, os.Args[2])
		}
		mr.Wait()
	} else {
		mapreduce.RunWorker(os.Args[2], os.Args[3], mapF, reduceF, 100, nil)
	}
}


================================================
FILE: src/main/lockc.go
================================================
package main

//
// see comments in lockd.go
//

import "lockservice"
import "os"
import "fmt"

func usage() {
	fmt.Printf("Usage: lockc -l|-u primaryport backupport lockname\n")
	os.Exit(1)
}

func main() {
	if len(os.Args) == 5 {
		ck := lockservice.MakeClerk(os.Args[2], os.Args[3])
		var ok bool
		if os.Args[1] == "-l" {
			ok = ck.Lock(os.Args[4])
		} else if os.Args[1] == "-u" {
			ok = ck.Unlock(os.Args[4])
		} else {
			usage()
		}
		fmt.Printf("reply: %v\n", ok)
	} else {
		usage()
	}
}


================================================
FILE: src/main/lockd.go
================================================
package main

// export GOPATH=~/6.824
// go build lockd.go
// go build lockc.go
// ./lockd -p a b &
// ./lockd -b a b &
// ./lockc -l a b lx
// ./lockc -u a b lx
//
// on Athena, use /tmp/myname-a and /tmp/myname-b
// instead of a and b.

import "time"
import "lockservice"
import "os"
import "fmt"

func main() {
	if len(os.Args) == 4 && os.Args[1] == "-p" {
		lockservice.StartServer(os.Args[2], os.Args[3], true)
	} else if len(os.Args) == 4 && os.Args[1] == "-b" {
		lockservice.StartServer(os.Args[2], os.Args[3], false)
	} else {
		fmt.Printf("Usage: lockd -p|-b primaryport backupport\n")
		os.Exit(1)
	}
	for {
		time.Sleep(100 * time.Second)
	}
}


================================================
FILE: src/main/mr-challenge.txt
================================================
www: 8 pg-being_ernest.txt,pg-dorian_gray.txt,pg-frankenstein.txt,pg-grimm.txt,pg-huckleberry_finn.txt,pg-metamorphosis.txt,pg-sherlock_holmes.txt,pg-tom_sawyer.txt
year: 8 pg-being_ernest.txt,pg-dorian_gray.txt,pg-frankenstein.txt,pg-grimm.txt,pg-huckleberry_finn.txt,pg-metamorphosis.txt,pg-sherlock_holmes.txt,pg-tom_sawyer.txt
years: 8 pg-being_ernest.txt,pg-dorian_gray.txt,pg-frankenstein.txt,pg-grimm.txt,pg-huckleberry_finn.txt,pg-metamorphosis.txt,pg-sherlock_holmes.txt,pg-tom_sawyer.txt
yesterday: 8 pg-being_ernest.txt,pg-dorian_gray.txt,pg-frankenstein.txt,pg-grimm.txt,pg-huckleberry_finn.txt,pg-metamorphosis.txt,pg-sherlock_holmes.txt,pg-tom_sawyer.txt
yet: 8 pg-being_ernest.txt,pg-dorian_gray.txt,pg-frankenstein.txt,pg-grimm.txt,pg-huckleberry_finn.txt,pg-metamorphosis.txt,pg-sherlock_holmes.txt,pg-tom_sawyer.txt
you: 8 pg-being_ernest.txt,pg-dorian_gray.txt,pg-frankenstein.txt,pg-grimm.txt,pg-huckleberry_finn.txt,pg-metamorphosis.txt,pg-sherlock_holmes.txt,pg-tom_sawyer.txt
young: 8 pg-being_ernest.txt,pg-dorian_gray.txt,pg-frankenstein.txt,pg-grimm.txt,pg-huckleberry_finn.txt,pg-metamorphosis.txt,pg-sherlock_holmes.txt,pg-tom_sawyer.txt
your: 8 pg-being_ernest.txt,pg-dorian_gray.txt,pg-frankenstein.txt,pg-grimm.txt,pg-huckleberry_finn.txt,pg-metamorphosis.txt,pg-sherlock_holmes.txt,pg-tom_sawyer.txt
yourself: 8 pg-being_ernest.txt,pg-dorian_gray.txt,pg-frankenstein.txt,pg-grimm.txt,pg-huckleberry_finn.txt,pg-metamorphosis.txt,pg-sherlock_holmes.txt,pg-tom_sawyer.txt
zip: 8 pg-being_ernest.txt,pg-dorian_gray.txt,pg-frankenstein.txt,pg-grimm.txt,pg-huckleberry_finn.txt,pg-metamorphosis.txt,pg-sherlock_holmes.txt,pg-tom_sawyer.txt


================================================
FILE: src/main/mr-testout.txt
================================================
that: 7871
it: 7987
in: 8415
was: 8578
a: 13382
of: 13536
I: 14296
to: 16079
and: 23612
the: 29748


================================================
FILE: src/main/pbc.go
================================================
package main

//
// pbservice client application
//
// export GOPATH=~/6.824
// go build viewd.go
// go build pbd.go
// go build pbc.go
// ./viewd /tmp/rtm-v &
// ./pbd /tmp/rtm-v /tmp/rtm-1 &
// ./pbd /tmp/rtm-v /tmp/rtm-2 &
// ./pbc /tmp/rtm-v key1 value1
// ./pbc /tmp/rtm-v key1
//
// change "rtm" to your user name.
// start the pbd programs in separate windows and kill
// and restart them to exercise fault tolerance.
//

import "pbservice"
import "os"
import "fmt"

func usage() {
	fmt.Printf("Usage: pbc viewport key\n")
	fmt.Printf("       pbc viewport key value\n")
	os.Exit(1)
}

func main() {
	if len(os.Args) == 3 {
		// get
		ck := pbservice.MakeClerk(os.Args[1], "")
		v := ck.Get(os.Args[2])
		fmt.Printf("%v\n", v)
	} else if len(os.Args) == 4 {
		// put
		ck := pbservice.MakeClerk(os.Args[1], "")
		ck.Put(os.Args[2], os.Args[3])
	} else {
		usage()
	}
}


================================================
FILE: src/main/pbd.go
================================================
package main

//
// see directions in pbc.go
//

import "time"
import "pbservice"
import "os"
import "fmt"

func main() {
	if len(os.Args) != 3 {
		fmt.Printf("Usage: pbd viewport myport\n")
		os.Exit(1)
	}

	pbservice.StartServer(os.Args[1], os.Args[2])

	for {
		time.Sleep(100 * time.Second)
	}
}


================================================
FILE: src/main/pg-being_ernest.txt
================================================
The Project Gutenberg eBook, The Importance of Being Earnest, by Oscar
Wilde


This eBook is for the use of anyone anywhere at no cost and with
almost no restrictions whatsoever.  You may copy it, give it away or
re-use it under the terms of the Project Gutenberg License included
with this eBook or online at www.gutenberg.org





Title: The Importance of Being Earnest
       A Trivial Comedy for Serious People


Author: Oscar Wilde



Release Date: August 29, 2006  [eBook #844]

Language: English

Character set encoding: ISO-646-US (US-ASCII)


***START OF THE PROJECT GUTENBERG EBOOK THE IMPORTANCE OF BEING EARNEST***






Transcribed from the 1915 Methuen & Co. Ltd. edition by David Price,
email ccx074@pglaf.org





The Importance of Being Earnest
A Trivial Comedy for Serious People


THE PERSONS IN THE PLAY


John Worthing, J.P.
Algernon Moncrieff
Rev. Canon Chasuble, D.D.
Merriman, Butler
Lane, Manservant
Lady Bracknell
Hon. Gwendolen Fairfax
Cecily Cardew
Miss Prism, Governess




THE SCENES OF THE PLAY


ACT I.  Algernon Moncrieff's Flat in Half-Moon Street, W.

ACT II.  The Garden at the Manor House, Woolton.

ACT III.  Drawing-Room at the Manor House, Woolton.

TIME: The Present.




LONDON: ST. JAMES'S THEATRE


Lessee and Manager: Mr. George Alexander

February 14th, 1895

* * * * *

John Worthing, J.P.: Mr. George Alexander.
Algernon Moncrieff: Mr. Allen Aynesworth.
Rev. Canon Chasuble, D.D.: Mr. H. H. Vincent.
Merriman: Mr. Frank Dyall.
Lane: Mr. F. Kinsey Peile.
Lady Bracknell: Miss Rose Leclercq.
Hon. Gwendolen Fairfax: Miss Irene Vanbrugh.
Cecily Cardew: Miss Evelyn Millard.
Miss Prism: Mrs. George Canninge.




FIRST ACT


SCENE


Morning-room in Algernon's flat in Half-Moon Street.  The room is
luxuriously and artistically furnished.  The sound of a piano is heard in
the adjoining room.

[Lane is arranging afternoon tea on the table, and after the music has
ceased, Algernon enters.]

Algernon.  Did you hear what I was playing, Lane?

Lane.  I didn't think it polite to listen, sir.

Algernon.  I'm sorry for that, for your sake.  I don't play
accurately--any one can play accurately--but I play with wonderful
expression.  As far as the piano is concerned, sentiment is my forte.  I
keep science for Life.

Lane.  Yes, sir.

Algernon.  And, speaking of the science of Life, have you got the
cucumber sandwiches cut for Lady Bracknell?

Lane.  Yes, sir.  [Hands them on a salver.]

Algernon.  [Inspects them, takes two, and sits down on the sofa.]  Oh! . . .
by the way, Lane, I see from your book that on Thursday night, when
Lord Shoreman and Mr. Worthing were dining with me, eight bottles of
champagne are entered as having been consumed.

Lane.  Yes, sir; eight bottles and a pint.

Algernon.  Why is it that at a bachelor's establishment the servants
invariably drink the champagne?  I ask merely for information.

Lane.  I attribute it to the superior quality of the wine, sir.  I have
often observed that in married households the champagne is rarely of a
first-rate brand.

Algernon.  Good heavens!  Is marriage so demoralising as that?

Lane.  I believe it _is_ a very pleasant state, sir.  I have had very
little experience of it myself up to the present.  I have only been
married once.  That was in consequence of a misunderstanding between
myself and a young person.

Algernon.  [Languidly_._]  I don't know that I am much interested in your
family life, Lane.

Lane.  No, sir; it is not a very interesting subject.  I never think of
it myself.

Algernon.  Very natural, I am sure.  That will do, Lane, thank you.

Lane.  Thank you, sir.  [Lane goes out.]

Algernon.  Lane's views on marriage seem somewhat lax.  Really, if the
lower orders don't set us a good example, what on earth is the use of
them?  They seem, as a class, to have absolutely no sense of moral
responsibility.

[Enter Lane.]

Lane.  Mr. Ernest Worthing.

[Enter Jack.]

[Lane goes out_._]

Algernon.  How are you, my dear Ernest?  What brings you up to town?

Jack.  Oh, pleasure, pleasure!  What else should bring one anywhere?
Eating as usual, I see, Algy!

Algernon.  [Stiffly_._]  I believe it is customary in good society to
take some slight refreshment at five o'clock.  Where have you been since
last Thursday?

Jack.  [Sitting down on the sofa.]  In the country.

Algernon.  What on earth do you do there?

Jack.  [Pulling off his gloves_._]  When one is in town one amuses
oneself.  When one is in the country one amuses other people.  It is
excessively boring.

Algernon.  And who are the people you amuse?

Jack.  [Airily_._]  Oh, neighbours, neighbours.

Algernon.  Got nice neighbours in your part of Shropshire?

Jack.  Perfectly horrid!  Never speak to one of them.

Algernon.  How immensely you must amuse them!  [Goes over and takes
sandwich.]  By the way, Shropshire is your county, is it not?

Jack.  Eh?  Shropshire?  Yes, of course.  Hallo!  Why all these cups?  Why
cucumber sandwiches?  Why such reckless extravagance in one so young?  Who
is coming to tea?

Algernon.  Oh! merely Aunt Augusta and Gwendolen.

Jack.  How perfectly delightful!

Algernon.  Yes, that is all very well; but I am afraid Aunt Augusta won't
quite approve of your being here.

Jack.  May I ask why?

Algernon.  My dear fellow, the way you flirt with Gwendolen is perfectly
disgraceful.  It is almost as bad as the way Gwendolen flirts with you.

Jack.  I am in love with Gwendolen.  I have come up to town expressly to
propose to her.

Algernon.  I thought you had come up for pleasure? . . . I call that
business.

Jack.  How utterly unromantic you are!

Algernon.  I really don't see anything romantic in proposing.  It is very
romantic to be in love.  But there is nothing romantic about a definite
proposal.  Why, one may be accepted.  One usually is, I believe.  Then
the excitement is all over.  The very essence of romance is uncertainty.
If ever I get married, I'll certainly try to forget the fact.

Jack.  I have no doubt about that, dear Algy.  The Divorce Court was
specially invented for people whose memories are so curiously
constituted.

Algernon.  Oh! there is no use speculating on that subject.  Divorces are
made in Heaven--[Jack puts out his hand to take a sandwich.  Algernon at
once interferes.]  Please don't touch the cucumber sandwiches.  They are
ordered specially for Aunt Augusta.  [Takes one and eats it.]

Jack.  Well, you have been eating them all the time.

Algernon.  That is quite a different matter.  She is my aunt.  [Takes
plate from below.]  Have some bread and butter.  The bread and butter is
for Gwendolen.  Gwendolen is devoted to bread and butter.

Jack.  [Advancing to table and helping himself.]  And very good bread and
butter it is too.

Algernon.  Well, my dear fellow, you need not eat as if you were going to
eat it all.  You behave as if you were married to her already.  You are
not married to her already, and I don't think you ever will be.

Jack.  Why on earth do you say that?

Algernon.  Well, in the first place girls never marry the men they flirt
with.  Girls don't think it right.

Jack.  Oh, that is nonsense!

Algernon.  It isn't.  It is a great truth.  It accounts for the
extraordinary number of bachelors that one sees all over the place.  In
the second place, I don't give my consent.

Jack.  Your consent!

Algernon.  My dear fellow, Gwendolen is my first cousin.  And before I
allow you to marry her, you will have to clear up the whole question of
Cecily.  [Rings bell.]

Jack.  Cecily!  What on earth do you mean?  What do you mean, Algy, by
Cecily!  I don't know any one of the name of Cecily.

[Enter Lane.]

Algernon.  Bring me that cigarette case Mr. Worthing left in the smoking-
room the last time he dined here.

Lane.  Yes, sir.  [Lane goes out.]

Jack.  Do you mean to say you have had my cigarette case all this time?  I
wish to goodness you had let me know.  I have been writing frantic
letters to Scotland Yard about it.  I was very nearly offering a large
reward.

Algernon.  Well, I wish you would offer one.  I happen to be more than
usually hard up.

Jack.  There is no good offering a large reward now that the thing is
found.

[Enter Lane with the cigarette case on a salver.  Algernon takes it at
once.  Lane goes out.]

Algernon.  I think that is rather mean of you, Ernest, I must say.  [Opens
case and examines it.]  However, it makes no matter, for, now that I look
at the inscription inside, I find that the thing isn't yours after all.

Jack.  Of course it's mine.  [Moving to him.]  You have seen me with it a
hundred times, and you have no right whatsoever to read what is written
inside.  It is a very ungentlemanly thing to read a private cigarette
case.

Algernon.  Oh! it is absurd to have a hard and fast rule about what one
should read and what one shouldn't.  More than half of modern culture
depends on what one shouldn't read.

Jack.  I am quite aware of the fact, and I don't propose to discuss
modern culture.  It isn't the sort of thing one should talk of in
private.  I simply want my cigarette case back.

Algernon.  Yes; but this isn't your cigarette case.  This cigarette case
is a present from some one of the name of Cecily, and you said you didn't
know any one of that name.

Jack.  Well, if you want to know, Cecily happens to be my aunt.

Algernon.  Your aunt!

Jack.  Yes.  Charming old lady she is, too.  Lives at Tunbridge Wells.
Just give it back to me, Algy.

Algernon.  [Retreating to back of sofa.]  But why does she call herself
little Cecily if she is your aunt and lives at Tunbridge Wells?
[Reading.]  'From little Cecily with her fondest love.'

Jack.  [Moving to sofa and kneeling upon it.]  My dear fellow, what on
earth is there in that?  Some aunts are tall, some aunts are not tall.
That is a matter that surely an aunt may be allowed to decide for
herself.  You seem to think that every aunt should be exactly like your
aunt!  That is absurd!  For Heaven's sake give me back my cigarette case.
[Follows Algernon round the room.]

Algernon.  Yes.  But why does your aunt call you her uncle?  'From little
Cecily, with her fondest love to her dear Uncle Jack.'  There is no
objection, I admit, to an aunt being a small aunt, but why an aunt, no
matter what her size may be, should call her own nephew her uncle, I
can't quite make out.  Besides, your name isn't Jack at all; it is
Ernest.

Jack.  It isn't Ernest; it's Jack.

Algernon.  You have always told me it was Ernest.  I have introduced you
to every one as Ernest.  You answer to the name of Ernest.  You look as
if your name was Ernest.  You are the most earnest-looking person I ever
saw in my life.  It is perfectly absurd your saying that your name isn't
Ernest.  It's on your cards.  Here is one of them.  [Taking it from
case.]  'Mr. Ernest Worthing, B. 4, The Albany.'  I'll keep this as a
proof that your name is Ernest if ever you attempt to deny it to me, or
to Gwendolen, or to any one else.  [Puts the card in his pocket.]

Jack.  Well, my name is Ernest in town and Jack in the country, and the
cigarette case was given to me in the country.

Algernon.  Yes, but that does not account for the fact that your small
Aunt Cecily, who lives at Tunbridge Wells, calls you her dear uncle.
Come, old boy, you had much better have the thing out at once.

Jack.  My dear Algy, you talk exactly as if you were a dentist.  It is
very vulgar to talk like a dentist when one isn't a dentist.  It produces
a false impression.

Algernon.  Well, that is exactly what dentists always do.  Now, go on!
Tell me the whole thing.  I may mention that I have always suspected you
of being a confirmed and secret Bunburyist; and I am quite sure of it
now.

Jack.  Bunburyist? What on earth do you mean by a Bunburyist?

Algernon.  I'll reveal to you the meaning of that incomparable expression
as soon as you are kind enough to inform me why you are Ernest in town
and Jack in the country.

Jack.  Well, produce my cigarette case first.

Algernon.  Here it is.  [Hands cigarette case.]  Now produce your
explanation, and pray make it improbable.  [Sits on sofa.]

Jack.  My dear fellow, there is nothing improbable about my explanation
at all.  In fact it's perfectly ordinary.  Old Mr. Thomas Cardew, who
adopted me when I was a little boy, made me in his will guardian to his
grand-daughter, Miss Cecily Cardew.  Cecily, who addresses me as her
uncle from motives of respect that you could not possibly appreciate,
lives at my place in the country under the charge of her admirable
governess, Miss Prism.

Algernon.  Where is that place in the country, by the way?

Jack.  That is nothing to you, dear boy.  You are not going to be invited
. . . I may tell you candidly that the place is not in Shropshire.

Algernon.  I suspected that, my dear fellow!  I have Bunburyed all over
Shropshire on two separate occasions.  Now, go on.  Why are you Ernest in
town and Jack in the country?

Jack.  My dear Algy, I don't know whether you will be able to understand
my real motives.  You are hardly serious enough.  When one is placed in
the position of guardian, one has to adopt a very high moral tone on all
subjects.  It's one's duty to do so.  And as a high moral tone can hardly
be said to conduce very much to either one's health or one's happiness,
in order to get up to town I have always pretended to have a younger
brother of the name of Ernest, who lives in the Albany, and gets into the
most dreadful scrapes.  That, my dear Algy, is the whole truth pure and
simple.

Algernon.  The truth is rarely pure and never simple.  Modern life would
be very tedious if it were either, and modern literature a complete
impossibility!

Jack.  That wouldn't be at all a bad thing.

Algernon.  Literary criticism is not your forte, my dear fellow.  Don't
try it.  You should leave that to people who haven't been at a
University.  They do it so well in the daily papers.  What you really are
is a Bunburyist.  I was quite right in saying you were a Bunburyist.  You
are one of the most advanced Bunburyists I know.

Jack.  What on earth do you mean?

Algernon.  You have invented a very useful younger brother called Ernest,
in order that you may be able to come up to town as often as you like.  I
have invented an invaluable permanent invalid called Bunbury, in order
that I may be able to go down into the country whenever I choose.  Bunbury
is perfectly invaluable.  If it wasn't for Bunbury's extraordinary bad
health, for instance, I wouldn't be able to dine with you at Willis's to-
night, for I have been really engaged to Aunt Augusta for more than a
week.

Jack.  I haven't asked you to dine with me anywhere to-night.

Algernon.  I know.  You are absurdly careless about sending out
invitations.  It is very foolish of you.  Nothing annoys people so much
as not receiving invitations.

Jack.  You had much better dine with your Aunt Augusta.

Algernon.  I haven't the smallest intention of doing anything of the
kind.  To begin with, I dined there on Monday, and once a week is quite
enough to dine with one's own relations.  In the second place, whenever I
do dine there I am always treated as a member of the family, and sent
down with either no woman at all, or two.  In the third place, I know
perfectly well whom she will place me next to, to-night.  She will place
me next Mary Farquhar, who always flirts with her own husband across the
dinner-table.  That is not very pleasant.  Indeed, it is not even decent
. . . and that sort of thing is enormously on the increase.  The amount
of women in London who flirt with their own husbands is perfectly
scandalous.  It looks so bad.  It is simply washing one's clean linen in
public.  Besides, now that I know you to be a confirmed Bunburyist I
naturally want to talk to you about Bunburying.  I want to tell you the
rules.

Jack.  I'm not a Bunburyist at all.  If Gwendolen accepts me, I am going
to kill my brother, indeed I think I'll kill him in any case.  Cecily is
a little too much interested in him.  It is rather a bore.  So I am going
to get rid of Ernest.  And I strongly advise you to do the same with Mr.
. . . with your invalid friend who has the absurd name.

Algernon.  Nothing will induce me to part with Bunbury, and if you ever
get married, which seems to me extremely problematic, you will be very
glad to know Bunbury.  A man who marries without knowing Bunbury has a
very tedious time of it.

Jack.  That is nonsense.  If I marry a charming girl like Gwendolen, and
she is the only girl I ever saw in my life that I would marry, I
certainly won't want to know Bunbury.

Algernon.  Then your wife will.  You don't seem to realise, that in
married life three is company and two is none.

Jack.  [Sententiously.]  That, my dear young friend, is the theory that
the corrupt French Drama has been propounding for the last fifty years.

Algernon.  Yes; and that the happy English home has proved in half the
time.

Jack.  For heaven's sake, don't try to be cynical.  It's perfectly easy
to be cynical.

Algernon.  My dear fellow, it isn't easy to be anything nowadays.  There's
such a lot of beastly competition about.  [The sound of an electric bell
is heard.]  Ah! that must be Aunt Augusta.  Only relatives, or creditors,
ever ring in that Wagnerian manner.  Now, if I get her out of the way for
ten minutes, so that you can have an opportunity for proposing to
Gwendolen, may I dine with you to-night at Willis's?

Jack.  I suppose so, if you want to.

Algernon.  Yes, but you must be serious about it.  I hate people who are
not serious about meals.  It is so shallow of them.

[Enter Lane.]

Lane.  Lady Bracknell and Miss Fairfax.

[Algernon goes forward to meet them.  Enter Lady Bracknell and
Gwendolen.]

Lady Bracknell.  Good afternoon, dear Algernon, I hope you are behaving
very well.

Algernon.  I'm feeling very well, Aunt Augusta.

Lady Bracknell.  That's not quite the same thing.  In fact the two things
rarely go together.  [Sees Jack and bows to him with icy coldness.]

Algernon.  [To Gwendolen.]  Dear me, you are smart!

Gwendolen.  I am always smart!  Am I not, Mr. Worthing?

Jack.  You're quite perfect, Miss Fairfax.

Gwendolen.  Oh! I hope I am not that.  It would leave no room for
developments, and I intend to develop in many directions.  [Gwendolen and
Jack sit down together in the corner.]

Lady Bracknell.  I'm sorry if we are a little late, Algernon, but I was
obliged to call on dear Lady Harbury.  I hadn't been there since her poor
husband's death.  I never saw a woman so altered; she looks quite twenty
years younger.  And now I'll have a cup of tea, and one of those nice
cucumber sandwiches you promised me.

Algernon.  Certainly, Aunt Augusta.  [Goes over to tea-table.]

Lady Bracknell.  Won't you come and sit here, Gwendolen?

Gwendolen.  Thanks, mamma, I'm quite comfortable where I am.

Algernon.  [Picking up empty plate in horror.]  Good heavens!  Lane!  Why
are there no cucumber sandwiches?  I ordered them specially.

Lane.  [Gravely.]  There were no cucumbers in the market this morning,
sir.  I went down twice.

Algernon.  No cucumbers!

Lane.  No, sir.  Not even for ready money.

Algernon.  That will do, Lane, thank you.

Lane.  Thank you, sir.  [Goes out.]

Algernon.  I am greatly distressed, Aunt Augusta, about there being no
cucumbers, not even for ready money.

Lady Bracknell.  It really makes no matter, Algernon.  I had some
crumpets with Lady Harbury, who seems to me to be living entirely for
pleasure now.

Algernon.  I hear her hair has turned quite gold from grief.

Lady Bracknell.  It certainly has changed its colour.  From what cause I,
of course, cannot say.  [Algernon crosses and hands tea.]  Thank you.
I've quite a treat for you to-night, Algernon.  I am going to send you
down with Mary Farquhar.  She is such a nice woman, and so attentive to
her husband.  It's delightful to watch them.

Algernon.  I am afraid, Aunt Augusta, I shall have to give up the
pleasure of dining with you to-night after all.

Lady Bracknell.  [Frowning.]  I hope not, Algernon.  It would put my
table completely out.  Your uncle would have to dine upstairs.
Fortunately he is accustomed to that.

Algernon.  It is a great bore, and, I need hardly say, a terrible
disappointment to me, but the fact is I have just had a telegram to say
that my poor friend Bunbury is very ill again.  [Exchanges glances with
Jack.]  They seem to think I should be with him.

Lady Bracknell.  It is very strange.  This Mr. Bunbury seems to suffer
from curiously bad health.

Algernon.  Yes; poor Bunbury is a dreadful invalid.

Lady Bracknell.  Well, I must say, Algernon, that I think it is high time
that Mr. Bunbury made up his mind whether he was going to live or to die.
This shilly-shallying with the question is absurd.  Nor do I in any way
approve of the modern sympathy with invalids.  I consider it morbid.
Illness of any kind is hardly a thing to be encouraged in others.  Health
is the primary duty of life.  I am always telling that to your poor
uncle, but he never seems to take much notice . . . as far as any
improvement in his ailment goes.  I should be much obliged if you would
ask Mr. Bunbury, from me, to be kind enough not to have a relapse on
Saturday, for I rely on you to arrange my music for me.  It is my last
reception, and one wants something that will encourage conversation,
particularly at the end of the season when every one has practically said
whatever they had to say, which, in most cases, was probably not much.

Algernon.  I'll speak to Bunbury, Aunt Augusta, if he is still conscious,
and I think I can promise you he'll be all right by Saturday.  Of course
the music is a great difficulty.  You see, if one plays good music,
people don't listen, and if one plays bad music people don't talk.  But
I'll run over the programme I've drawn out, if you will kindly come into
the next room for a moment.

Lady Bracknell.  Thank you, Algernon.  It is very thoughtful of you.
[Rising, and following Algernon.]  I'm sure the programme will be
delightful, after a few expurgations.  French songs I cannot possibly
allow.  People always seem to think that they are improper, and either
look shocked, which is vulgar, or laugh, which is worse.  But German
sounds a thoroughly respectable language, and indeed, I believe is so.
Gwendolen, you will accompany me.

Gwendolen.  Certainly, mamma.

[Lady Bracknell and Algernon go into the music-room, Gwendolen remains
behind.]

Jack.  Charming day it has been, Miss Fairfax.

Gwendolen.  Pray don't talk to me about the weather, Mr. Worthing.
Whenever people talk to me about the weather, I always feel quite certain
that they mean something else.  And that makes me so nervous.

Jack.  I do mean something else.

Gwendolen.  I thought so.  In fact, I am never wrong.

Jack.  And I would like to be allowed to take advantage of Lady
Bracknell's temporary absence . . .

Gwendolen.  I would certainly advise you to do so.  Mamma has a way of
coming back suddenly into a room that I have often had to speak to her
about.

Jack.  [Nervously.]  Miss Fairfax, ever since I met you I have admired
you more than any girl . . . I have ever met since . . . I met you.

Gwendolen.  Yes, I am quite well aware of the fact.  And I often wish
that in public, at any rate, you had been more demonstrative.  For me you
have always had an irresistible fascination.  Even before I met you I was
far from indifferent to you.  [Jack looks at her in amazement.]  We live,
as I hope you know, Mr. Worthing, in an age of ideals.  The fact is
constantly mentioned in the more expensive monthly magazines, and has
reached the provincial pulpits, I am told; and my ideal has always been
to love some one of the name of Ernest.  There is something in that name
that inspires absolute confidence.  The moment Algernon first mentioned
to me that he had a friend called Ernest, I knew I was destined to love
you.

Jack.  You really love me, Gwendolen?

Gwendolen.  Passionately!

Jack.  Darling!  You don't know how happy you've made me.

Gwendolen.  My own Ernest!

Jack.  But you don't really mean to say that you couldn't love me if my
name wasn't Ernest?

Gwendolen.  But your name is Ernest.

Jack.  Yes, I know it is.  But supposing it was something else?  Do you
mean to say you couldn't love me then?

Gwendolen.  [Glibly.]  Ah! that is clearly a metaphysical speculation,
and like most metaphysical speculations has very little reference at all
to the actual facts of real life, as we know them.

Jack.  Personally, darling, to speak quite candidly, I don't much care
about the name of Ernest . . . I don't think the name suits me at all.

Gwendolen.  It suits you perfectly.  It is a divine name.  It has a music
of its own.  It produces vibrations.

Jack.  Well, really, Gwendolen, I must say that I think there are lots of
other much nicer names.  I think Jack, for instance, a charming name.

Gwendolen.  Jack? . . . No, there is very little music in the name Jack,
if any at all, indeed.  It does not thrill.  It produces absolutely no
vibrations . . . I have known several Jacks, and they all, without
exception, were more than usually plain.  Besides, Jack is a notorious
domesticity for John!  And I pity any woman who is married to a man
called John.  She would probably never be allowed to know the entrancing
pleasure of a single moment's solitude.  The only really safe name is
Ernest.

Jack.  Gwendolen, I must get christened at once--I mean we must get
married at once.  There is no time to be lost.

Gwendolen.  Married, Mr. Worthing?

Jack.  [Astounded.]  Well . . . surely.  You know that I love you, and
you led me to believe, Miss Fairfax, that you were not absolutely
indifferent to me.

Gwendolen.  I adore you.  But you haven't proposed to me yet.  Nothing
has been said at all about marriage.  The subject has not even been
touched on.

Jack.  Well . . . may I propose to you now?

Gwendolen.  I think it would be an admirable opportunity.  And to spare
you any possible disappointment, Mr. Worthing, I think it only fair to
tell you quite frankly before-hand that I am fully determined to accept
you.

Jack.  Gwendolen!

Gwendolen.  Yes, Mr. Worthing, what have you got to say to me?

Jack.  You know what I have got to say to you.

Gwendolen.  Yes, but you don't say it.

Jack.  Gwendolen, will you marry me?  [Goes on his knees.]

Gwendolen.  Of course I will, darling.  How long you have been about it!
I am afraid you have had very little experience in how to propose.

Jack.  My own one, I have never loved any one in the world but you.

Gwendolen.  Yes, but men often propose for practice.  I know my brother
Gerald does.  All my girl-friends tell me so.  What wonderfully blue eyes
you have, Ernest!  They are quite, quite, blue.  I hope you will always
look at me just like that, especially when there are other people
present.  [Enter Lady Bracknell.]

Lady Bracknell.  Mr. Worthing!  Rise, sir, from this semi-recumbent
posture.  It is most indecorous.

Gwendolen.  Mamma!  [He tries to rise; she restrains him.]  I must beg
you to retire.  This is no place for you.  Besides, Mr. Worthing has not
quite finished yet.

Lady Bracknell.  Finished what, may I ask?

Gwendolen.  I am engaged to Mr. Worthing, mamma.  [They rise together.]

Lady Bracknell.  Pardon me, you are not engaged to any one.  When you do
become engaged to some one, I, or your father, should his health permit
him, will inform you of the fact.  An engagement should come on a young
girl as a surprise, pleasant or unpleasant, as the case may be.  It is
hardly a matter that she could be allowed to arrange for herself . . .
And now I have a few questions to put to you, Mr. Worthing.  While I am
making these inquiries, you, Gwendolen, will wait for me below in the
carriage.

Gwendolen.  [Reproachfully.]  Mamma!

Lady Bracknell.  In the carriage, Gwendolen!  [Gwendolen goes to the
door.  She and Jack blow kisses to each other behind Lady Bracknell's
back.  Lady Bracknell looks vaguely about as if she could not understand
what the noise was.  Finally turns round.]  Gwendolen, the carriage!

Gwendolen.  Yes, mamma.  [Goes out, looking back at Jack.]

Lady Bracknell.  [Sitting down.]  You can take a seat, Mr. Worthing.

[Looks in her pocket for note-book and pencil.]

Jack.  Thank you, Lady Bracknell, I prefer standing.

Lady Bracknell.  [Pencil and note-book in hand.]  I feel bound to tell
you that you are not down on my list of eligible young men, although I
have the same list as the dear Duchess of Bolton has.  We work together,
in fact.  However, I am quite ready to enter your name, should your
answers be what a really affectionate mother requires.  Do you smoke?

Jack.  Well, yes, I must admit I smoke.

Lady Bracknell.  I am glad to hear it.  A man should always have an
occupation of some kind.  There are far too many idle men in London as it
is.  How old are you?

Jack.  Twenty-nine.

Lady Bracknell.  A very good age to be married at.  I have always been of
opinion that a man who desires to get married should know either
everything or nothing.  Which do you know?

Jack.  [After some hesitation.]  I know nothing, Lady Bracknell.

Lady Bracknell.  I am pleased to hear it.  I do not approve of anything
that tampers with natural ignorance.  Ignorance is like a delicate exotic
fruit; touch it and the bloom is gone.  The whole theory of modern
education is radically unsound.  Fortunately in England, at any rate,
education produces no effect whatsoever.  If it did, it would prove a
serious danger to the upper classes, and probably lead to acts of
violence in Grosvenor Square.  What is your income?

Jack.  Between seven and eight thousand a year.

Lady Bracknell.  [Makes a note in her book.]  In land, or in investments?

Jack.  In investments, chiefly.

Lady Bracknell.  That is satisfactory.  What between the duties expected
of one during one's lifetime, and the duties exacted from one after one's
death, land has ceased to be either a profit or a pleasure.  It gives one
position, and prevents one from keeping it up.  That's all that can be
said about land.

Jack.  I have a country house with some land, of course, attached to it,
about fifteen hundred acres, I believe; but I don't depend on that for my
real income.  In fact, as far as I can make out, the poachers are the
only people who make anything out of it.

Lady Bracknell.  A country house!  How many bedrooms?  Well, that point
can be cleared up afterwards.  You have a town house, I hope?  A girl
with a simple, unspoiled nature, like Gwendolen, could hardly be expected
to reside in the country.

Jack.  Well, I own a house in Belgrave Square, but it is let by the year
to Lady Bloxham.  Of course, I can get it back whenever I like, at six
months' notice.

Lady Bracknell.  Lady Bloxham?  I don't know her.

Jack.  Oh, she goes about very little.  She is a lady considerably
advanced in years.

Lady Bracknell.  Ah, nowadays that is no guarantee of respectability of
character.  What number in Belgrave Square?

Jack.  149.

Lady Bracknell.  [Shaking her head.]  The unfashionable side.  I thought
there was something.  However, that could easily be altered.

Jack.  Do you mean the fashion, or the side?

Lady Bracknell.  [Sternly.]  Both, if necessary, I presume.  What are
your politics?

Jack.  Well, I am afraid I really have none.  I am a Liberal Unionist.

Lady Bracknell.  Oh, they count as Tories.  They dine with us.  Or come
in the evening, at any rate.  Now to minor matters.  Are your parents
living?

Jack.  I have lost both my parents.

Lady Bracknell.  To lose one parent, Mr. Worthing, may be regarded as a
misfortune; to lose both looks like carelessness.  Who was your father?
He was evidently a man of some wealth.  Was he born in what the Radical
papers call the purple of commerce, or did he rise from the ranks of the
aristocracy?

Jack.  I am afraid I really don't know.  The fact is, Lady Bracknell, I
said I had lost my parents.  It would be nearer the truth to say that my
parents seem to have lost me . . . I don't actually know who I am by
birth.  I was . . . well, I was found.

Lady Bracknell.  Found!

Jack.  The late Mr. Thomas Cardew, an old gentleman of a very charitable
and kindly disposition, found me, and gave me the name of Worthing,
because he happened to have a first-class ticket for Worthing in his
pocket at the time.  Worthing is a place in Sussex.  It is a seaside
resort.

Lady Bracknell.  Where did the charitable gentleman who had a first-class
ticket for this seaside resort find you?

Jack.  [Gravely.]  In a hand-bag.

Lady Bracknell.  A hand-bag?

Jack.  [Very seriously.]  Yes, Lady Bracknell.  I was in a hand-bag--a
somewhat large, black leather hand-bag, with handles to it--an ordinary
hand-bag in fact.

Lady Bracknell.  In what locality did this Mr. James, or Thomas, Cardew
come across this ordinary hand-bag?

Jack.  In the cloak-room at Victoria Station.  It was given to him in
mistake for his own.

Lady Bracknell.  The cloak-room at Victoria Station?

Jack.  Yes.  The Brighton line.

Lady Bracknell.  The line is immaterial.  Mr. Worthing, I confess I feel
somewhat bewildered by what you have just told me.  To be born, or at any
rate bred, in a hand-bag, whether it had handles or not, seems to me to
display a contempt for the ordinary decencies of family life that reminds
one of the worst excesses of the French Revolution.  And I presume you
know what that unfortunate movement led to?  As for the particular
locality in which the hand-bag was found, a cloak-room at a railway
station might serve to conceal a social indiscretion--has probably,
indeed, been used for that purpose before now--but it could hardly be
regarded as an assured basis for a recognised position in good society.

Jack.  May I ask you then what you would advise me to do?  I need hardly
say I would do anything in the world to ensure Gwendolen's happiness.

Lady Bracknell.  I would strongly advise you, Mr. Worthing, to try and
acquire some relations as soon as possible, and to make a definite effort
to produce at any rate one parent, of either sex, before the season is
quite over.

Jack.  Well, I don't see how I could possibly manage to do that.  I can
produce the hand-bag at any moment.  It is in my dressing-room at home.  I
really think that should satisfy you, Lady Bracknell.

Lady Bracknell.  Me, sir!  What has it to do with me?  You can hardly
imagine that I and Lord Bracknell would dream of allowing our only
daughter--a girl brought up with the utmost care--to marry into a cloak-
room, and form an alliance with a parcel?  Good morning, Mr. Worthing!

[Lady Bracknell sweeps out in majestic indignation.]

Jack.  Good morning!  [Algernon, from the other room, strikes up the
Wedding March.  Jack looks perfectly furious, and goes to the door.]  For
goodness' sake don't play that ghastly tune, Algy.  How idiotic you are!

[The music stops and Algernon enters cheerily.]

Algernon.  Didn't it go off all right, old boy?  You don't mean to say
Gwendolen refused you?  I know it is a way she has.  She is always
refusing people.  I think it is most ill-natured of her.

Jack.  Oh, Gwendolen is as right as a trivet.  As far as she is
concerned, we are engaged.  Her mother is perfectly unbearable.  Never
met such a Gorgon . . . I don't really know what a Gorgon is like, but I
am quite sure that Lady Bracknell is one.  In any case, she is a monster,
without being a myth, which is rather unfair . . . I beg your pardon,
Algy, I suppose I shouldn't talk about your own aunt in that way before
you.

Algernon.  My dear boy, I love hearing my relations abused.  It is the
only thing that makes me put up with them at all.  Relations are simply a
tedious pack of people, who haven't got the remotest knowledge of how to
live, nor the smallest instinct about when to die.

Jack.  Oh, that is nonsense!

Algernon.  It isn't!

Jack.  Well, I won't argue about the matter.  You always want to argue
about things.

Algernon.  That is exactly what things were originally made for.

Jack.  Upon my word, if I thought that, I'd shoot myself . . . [A pause.]
You don't think there is any chance of Gwendolen becoming like her mother
in about a hundred and fifty years, do you, Algy?

Algernon.  All women become like their mothers.  That is their tragedy.
No man does.  That's his.

Jack.  Is that clever?

Algernon.  It is perfectly phrased! and quite as true as any observation
in civilised life should be.

Jack.  I am sick to death of cleverness.  Everybody is clever nowadays.
You can't go anywhere without meeting clever people.  The thing has
become an absolute public nuisance.  I wish to goodness we had a few
fools left.

Algernon.  We have.

Jack.  I should extremely like to meet them.  What do they talk about?

Algernon.  The fools?  Oh! about the clever people, of course.

Jack.  What fools!

Algernon.  By the way, did you tell Gwendolen the truth about your being
Ernest in town, and Jack in the country?

Jack.  [In a very patronising manner.]  My dear fellow, the truth isn't
quite the sort of thing one tells to a nice, sweet, refined girl.  What
extraordinary ideas you have about the way to behave to a woman!

Algernon.  The only way to behave to a woman is to make love to her, if
she is pretty, and to some one else, if she is plain.

Jack.  Oh, that is nonsense.

Algernon.  What about your brother?  What about the profligate Ernest?

Jack.  Oh, before the end of the week I shall have got rid of him.  I'll
say he died in Paris of apoplexy.  Lots of people die of apoplexy, quite
suddenly, don't they?

Algernon.  Yes, but it's hereditary, my dear fellow.  It's a sort of
thing that runs in families.  You had much better say a severe chill.

Jack.  You are sure a severe chill isn't hereditary, or anything of that
kind?

Algernon.  Of course it isn't!

Jack.  Very well, then.  My poor brother Ernest to carried off suddenly,
in Paris, by a severe chill.  That gets rid of him.

Algernon.  But I thought you said that . . . Miss Cardew was a little too
much interested in your poor brother Ernest?  Won't she feel his loss a
good deal?

Jack.  Oh, that is all right.  Cecily is not a silly romantic girl, I am
glad to say.  She has got a capital appetite, goes long walks, and pays
no attention at all to her lessons.

Algernon.  I would rather like to see Cecily.

Jack.  I will take very good care you never do.  She is excessively
pretty, and she is only just eighteen.

Algernon.  Have you told Gwendolen yet that you have an excessively
pretty ward who is only just eighteen?

Jack.  Oh! one doesn't blurt these things out to people.  Cecily and
Gwendolen are perfectly certain to be extremely great friends.  I'll bet
you anything you like that half an hour after they have met, they will be
calling each other sister.

Algernon.  Women only do that when they have called each other a lot of
other things first.  Now, my dear boy, if we want to get a good table at
Willis's, we really must go and dress.  Do you know it is nearly seven?

Jack.  [Irritably.]  Oh!  It always is nearly seven.

Algernon.  Well, I'm hungry.

Jack.  I never knew you when you weren't . . .

Algernon.  What shall we do after dinner?  Go to a theatre?

Jack.  Oh no!  I loathe listening.

Algernon.  Well, let us go to the Club?

Jack.  Oh, no!  I hate talking.

Algernon.  Well, we might trot round to the Empire at ten?

Jack.  Oh, no!  I can't bear looking at things.  It is so silly.

Algernon.  Well, what shall we do?

Jack.  Nothing!

Algernon.  It is awfully hard work doing nothing.  However, I don't mind
hard work where there is no definite object of any kind.

[Enter Lane.]

Lane.  Miss Fairfax.

[Enter Gwendolen.  Lane goes out.]

Algernon.  Gwendolen, upon my word!

Gwendolen.  Algy, kindly turn your back.  I have something very
particular to say to Mr. Worthing.

Algernon.  Really, Gwendolen, I don't think I can allow this at all.

Gwendolen.  Algy, you always adopt a strictly immoral attitude towards
life.  You are not quite old enough to do that.  [Algernon retires to the
fireplace.]

Jack.  My own darling!

Gwendolen.  Ernest, we may never be married.  From the expression on
mamma's face I fear we never shall.  Few parents nowadays pay any regard
to what their children say to them.  The old-fashioned respect for the
young is fast dying out.  Whatever influence I ever had over mamma, I
lost at the age of three.  But although she may prevent us from becoming
man and wife, and I may marry some one else, and marry often, nothing
that she can possibly do can alter my eternal devotion to you.

Jack.  Dear Gwendolen!

Gwendolen.  The story of your romantic origin, as related to me by mamma,
with unpleasing comments, has naturally stirred the deeper fibres of my
nature.  Your Christian name has an irresistible fascination.  The
simplicity of your character makes you exquisitely incomprehensible to
me.  Your town address at the Albany I have.  What is your address in the
country?

Jack.  The Manor House, Woolton, Hertfordshire.

[Algernon, who has been carefully listening, smiles to himself, and
writes the address on his shirt-cuff.  Then picks up the Railway Guide.]

Gwendolen.  There is a good postal service, I suppose?  It may be
necessary to do something desperate.  That of course will require serious
consideration.  I will communicate with you daily.

Jack.  My own one!

Gwendolen.  How long do you remain in town?

Jack.  Till Monday.

Gwendolen.  Good!  Algy, you may turn round now.

Algernon.  Thanks, I've turned round already.

Gwendolen.  You may also ring the bell.

Jack.  You will let me see you to your carriage, my own darling?

Gwendolen.  Certainly.

Jack.  [To Lane, who now enters.]  I will see Miss Fairfax out.

Lane.  Yes, sir.  [Jack and Gwendolen go off.]

[Lane presents several letters on a salver to Algernon.  It is to be
surmised that they are bills, as Algernon, after looking at the
envelopes, tears them up.]

Algernon.  A glass of sherry, Lane.

Lane.  Yes, sir.

Algernon.  To-morrow, Lane, I'm going Bunburying.

Lane.  Yes, sir.

Algernon.  I shall probably not be back till Monday.  You can put up my
dress clothes, my smoking jacket, and all the Bunbury suits . . .

Lane.  Yes, sir.  [Handing sherry.]

Algernon.  I hope to-morrow will be a fine day, Lane.

Lane.  It never is, sir.

Algernon.  Lane, you're a perfect pessimist.

Lane.  I do my best to give satisfaction, sir.

[Enter Jack.  Lane goes off.]

Jack.  There's a sensible, intellectual girl! the only girl I ever cared
for in my life.  [Algernon is laughing immoderately.]  What on earth are
you so amused at?

Algernon.  Oh, I'm a little anxious about poor Bunbury, that is all.

Jack.  If you don't take care, your friend Bunbury will get you into a
serious scrape some day.

Algernon.  I love scrapes.  They are the only things that are never
serious.

Jack.  Oh, that's nonsense, Algy.  You never talk anything but nonsense.

Algernon.  Nobody ever does.

[Jack looks indignantly at him, and leaves the room.  Algernon lights a
cigarette, reads his shirt-cuff, and smiles.]

ACT DROP




SECOND ACT


SCENE


Garden at the Manor House.  A flight of grey stone steps leads up to the
house.  The garden, an old-fashioned one, full of roses.  Time of year,
July.  Basket chairs, and a table covered with books, are set under a
large yew-tree.

[Miss Prism discovered seated at the table.  Cecily is at the back
watering flowers.]

Miss Prism.  [Calling.]  Cecily, Cecily!  Surely such a utilitarian
occupation as the watering of flowers is rather Moulton's duty than
yours?  Especially at a moment when intellectual pleasures await you.
Your German grammar is on the table.  Pray open it at page fifteen.  We
will repeat yesterday's lesson.

Cecily.  [Coming over very slowly.]  But I don't like German.  It isn't
at all a becoming language.  I know perfectly well that I look quite
plain after my German lesson.

Miss Prism.  Child, you know how anxious your guardian is that you should
improve yourself in every way.  He laid particular stress on your German,
as he was leaving for town yesterday.  Indeed, he always lays stress on
your German when he is leaving for town.

Cecily.  Dear Uncle Jack is so very serious!  Sometimes he is so serious
that I think he cannot be quite well.

Miss Prism.  [Drawing herself up.]  Your guardian enjoys the best of
health, and his gravity of demeanour is especially to be commended in one
so comparatively young as he is.  I know no one who has a higher sense of
duty and responsibility.

Cecily.  I suppose that is why he often looks a little bored when we
three are together.

Miss Prism.  Cecily!  I am surprised at you.  Mr. Worthing has many
troubles in his life.  Idle merriment and triviality would be out of
place in his conversation.  You must remember his constant anxiety about
that unfortunate young man his brother.

Cecily.  I wish Uncle Jack would allow that unfortunate young man, his
brother, to come down here sometimes.  We might have a good influence
over him, Miss Prism.  I am sure you certainly would.  You know German,
and geology, and things of that kind influence a man very much.  [Cecily
begins to write in her diary.]

Miss Prism.  [Shaking her head.]  I do not think that even I could
produce any effect on a character that according to his own brother's
admission is irretrievably weak and vacillating.  Indeed I am not sure
that I would desire to reclaim him.  I am not in favour of this modern
mania for turning bad people into good people at a moment's notice.  As a
man sows so let him reap.  You must put away your diary, Cecily.  I
really don't see why you should keep a diary at all.

Cecily.  I keep a diary in order to enter the wonderful secrets of my
life.  If I didn't write them down, I should probably forget all about
them.

Miss Prism.  Memory, my dear Cecily, is the diary that we all carry about
with us.

Cecily.  Yes, but it usually chronicles the things that have never
happened, and couldn't possibly have happened.  I believe that Memory is
responsible for nearly all the three-volume novels that Mudie sends us.

Miss Prism.  Do not speak slightingly of the three-volume novel, Cecily.
I wrote one myself in earlier days.

Cecily.  Did you really, Miss Prism?  How wonderfully clever you are!  I
hope it did not end happily?  I don't like novels that end happily.  They
depress me so much.

Miss Prism.  The good ended happily, and the bad unhappily.  That is what
Fiction means.

Cecily.  I suppose so.  But it seems very unfair.  And was your novel
ever published?

Miss Prism.  Alas! no.  The manuscript unfortunately was abandoned.
[Cecily starts.]  I use the word in the sense of lost or mislaid.  To
your work, child, these speculations are profitless.

Cecily.  [Smiling.]  But I see dear Dr. Chasuble coming up through the
garden.

Miss Prism.  [Rising and advancing.]  Dr. Chasuble!  This is indeed a
pleasure.

[Enter Canon Chasuble.]

Chasuble.  And how are we this morning?  Miss Prism, you are, I trust,
well?

Cecily.  Miss Prism has just been complaining of a slight headache.  I
think it would do her so much good to have a short stroll with you in the
Park, Dr. Chasuble.

Miss Prism.  Cecily, I have not mentioned anything about a headache.

Cecily.  No, dear Miss Prism, I know that, but I felt instinctively that
you had a headache.  Indeed I was thinking about that, and not about my
German lesson, when the Rector came in.

Chasuble.  I hope, Cecily, you are not inattentive.

Cecily.  Oh, I am afraid I am.

Chasuble.  That is strange.  Were I fortunate enough to be Miss Prism's
pupil, I would hang upon her lips.  [Miss Prism glares.]  I spoke
metaphorically.--My metaphor was drawn from bees.  Ahem!  Mr. Worthing, I
suppose, has not returned from town yet?

Miss Prism.  We do not expect him till Monday afternoon.

Chasuble.  Ah yes, he usually likes to spend his Sunday in London.  He is
not one of those whose sole aim is enjoyment, as, by all accounts, that
unfortunate young man his brother seems to be.  But I must not disturb
Egeria and her pupil any longer.

Miss Prism.  Egeria?  My name is Laetitia, Doctor.

Chasuble.  [Bowing.]  A classical allusion merely, drawn from the Pagan
authors.  I shall see you both no doubt at Evensong?

Miss Prism.  I think, dear Doctor, I will have a stroll with you.  I find
I have a headache after all, and a walk might do it good.

Chasuble.  With pleasure, Miss Prism, with pleasure.  We might go as far
as the schools and back.

Miss Prism.  That would be delightful.  Cecily, you will read your
Political Economy in my absence.  The chapter on the Fall of the Rupee
you may omit.  It is somewhat too sensational.  Even these metallic
problems have their melodramatic side.

[Goes down the garden with Dr. Chasuble.]

Cecily.  [Picks up books and throws them back on table.]  Horrid
Political Economy!  Horrid Geography!  Horrid, horrid German!

[Enter Merriman with a card on a salver.]

Merriman.  Mr. Ernest Worthing has just driven over from the station.  He
has brought his luggage with him.

Cecily.  [Takes the card and reads it.]  'Mr. Ernest Worthing, B. 4, The
Albany, W.'  Uncle Jack's brother!  Did you tell him Mr. Worthing was in
town?

Merriman.  Yes, Miss.  He seemed very much disappointed.  I mentioned
that you and Miss Prism were in the garden.  He said he was anxious to
speak to you privately for a moment.

Cecily.  Ask Mr. Ernest Worthing to come here.  I suppose you had better
talk to the housekeeper about a room for him.

Merriman.  Yes, Miss.

[Merriman goes off.]

Cecily.  I have never met any really wicked person before.  I feel rather
frightened.  I am so afraid he will look just like every one else.

[Enter Algernon, very gay and debonnair.]  He does!

Algernon.  [Raising his hat.]  You are my little cousin Cecily, I'm sure.

Cecily.  You are under some strange mistake.  I am not little.  In fact,
I believe I am more than usually tall for my age.  [Algernon is rather
taken aback.]  But I am your cousin Cecily.  You, I see from your card,
are Uncle Jack's brother, my cousin Ernest, my wicked cousin Ernest.

Algernon.  Oh! I am not really wicked at all, cousin Cecily.  You mustn't
think that I am wicked.

Cecily.  If you are not, then you have certainly been deceiving us all in
a very inexcusable manner.  I hope you have not been leading a double
life, pretending to be wicked and being really good all the time.  That
would be hypocrisy.

Algernon.  [Looks at her in amazement.]  Oh!  Of course I have been
rather reckless.

Cecily.  I am glad to hear it.

Algernon.  In fact, now you mention the subject, I have been very bad in
my own small way.

Cecily.  I don't think you should be so proud of that, though I am sure
it must have been very pleasant.

Algernon.  It is much pleasanter being here with you.

Cecily.  I can't understand how you are here at all.  Uncle Jack won't be
back till Monday afternoon.

Algernon.  That is a great disappointment.  I am obliged to go up by the
first train on Monday morning.  I have a business appointment that I am
anxious . . . to miss?

Cecily.  Couldn't you miss it anywhere but in London?

Algernon.  No: the appointment is in London.

Cecily.  Well, I know, of course, how important it is not to keep a
business engagement, if one wants to retain any sense of the beauty of
life, but still I think you had better wait till Uncle Jack arrives.  I
know he wants to speak to you about your emigrating.

Algernon.  About my what?

Cecily.  Your emigrating.  He has gone up to buy your outfit.

Algernon.  I certainly wouldn't let Jack buy my outfit.  He has no taste
in neckties at all.

Cecily.  I don't think you will require neckties.  Uncle Jack is sending
you to Australia.

Algernon.  Australia!  I'd sooner die.

Cecily.  Well, he said at dinner on Wednesday night, that you would have
to choose between this world, the next world, and Australia.

Algernon.  Oh, well!  The accounts I have received of Australia and the
next world, are not particularly encouraging.  This world is good enough
for me, cousin Cecily.

Cecily.  Yes, but are you good enough for it?

Algernon.  I'm afraid I'm not that.  That is why I want you to reform me.
You might make that your mission, if you don't mind, cousin Cecily.

Cecily.  I'm afraid I've no time, this afternoon.

Algernon.  Well, would you mind my reforming myself this afternoon?

Cecily.  It is rather Quixotic of you.  But I think you should try.

Algernon.  I will.  I feel better already.

Cecily.  You are looking a little worse.

Algernon.  That is because I am hungry.

Cecily.  How thoughtless of me.  I should have remembered that when one
is going to lead an entirely new life, one requires regular and wholesome
meals.  Won't you come in?

Algernon.  Thank you.  Might I have a buttonhole first?  I never have any
appetite unless I have a buttonhole first.

Cecily.  A Marechal Niel?  [Picks up scissors.]

Algernon.  No, I'd sooner have a pink rose.

Cecily.  Why?  [Cuts a flower.]

Algernon.  Because you are like a pink rose, Cousin Cecily.

Cecily.  I don't think it can be right for you to talk to me like that.
Miss Prism never says such things to me.

Algernon.  Then Miss Prism is a short-sighted old lady.  [Cecily puts the
rose in his buttonhole.]  You are the prettiest girl I ever saw.

Cecily.  Miss Prism says that all good looks are a snare.

Algernon.  They are a snare that every sensible man would like to be
caught in.

Cecily.  Oh, I don't think I would care to catch a sensible man.  I
shouldn't know what to talk to him about.

[They pass into the house.  Miss Prism and Dr. Chasuble return.]

Miss Prism.  You are too much alone, dear Dr. Chasuble.  You should get
married.  A misanthrope I can understand--a womanthrope, never!

Chasuble.  [With a scholar's shudder.]  Believe me, I do not deserve so
neologistic a phrase.  The precept as well as the practice of the
Primitive Church was distinctly against matrimony.

Miss Prism.  [Sententiously.]  That is obviously the reason why the
Primitive Church has not lasted up to the present day.  And you do not
seem to realise, dear Doctor, that by persistently remaining single, a
man converts himself into a permanent public temptation.  Men should be
more careful; this very celibacy leads weaker vessels astray.

Chasuble.  But is a man not equally attractive when married?

Miss Prism.  No married man is ever attractive except to his wife.

Chasuble.  And often, I've been told, not even to her.

Miss Prism.  That depends on the intellectual sympathies of the woman.
Maturity can always be depended on.  Ripeness can be trusted.  Young
women are green.  [Dr. Chasuble starts.]  I spoke horticulturally.  My
metaphor was drawn from fruits.  But where is Cecily?

Chasuble.  Perhaps she followed us to the schools.

[Enter Jack slowly from the back of the garden.  He is dressed in the
deepest mourning, with crape hatband and black gloves.]

Miss Prism.  Mr. Worthing!

Chasuble.  Mr. Worthing?

Miss Prism.  This is indeed a surprise.  We did not look for you till
Monday afternoon.

Jack.  [Shakes Miss Prism's hand in a tragic manner.]  I have returned
sooner than I expected.  Dr. Chasuble, I hope you are well?

Chasuble.  Dear Mr. Worthing, I trust this garb of woe does not betoken
some terrible calamity?

Jack.  My brother.

Miss Prism.  More shameful debts and extravagance?

Chasuble.  Still leading his life of pleasure?

Jack.  [Shaking his head.]  Dead!

Chasuble.  Your brother Ernest dead?

Jack.  Quite dead.

Miss Prism.  What a lesson for him!  I trust he will profit by it.

Chasuble.  Mr. Worthing, I offer you my sincere condolence.  You have at
least the consolation of knowing that you were always the most generous
and forgiving of brothers.

Jack.  Poor Ernest!  He had many faults, but it is a sad, sad blow.

Chasuble.  Very sad indeed.  Were you with him at the end?

Jack.  No.  He died abroad; in Paris, in fact.  I had a telegram last
night from the manager of the Grand Hotel.

Chasuble.  Was the cause of death mentioned?

Jack.  A severe chill, it seems.

Miss Prism.  As a man sows, so shall he reap.

Chasuble.  [Raising his hand.]  Charity, dear Miss Prism, charity!  None
of us are perfect.  I myself am peculiarly susceptible to draughts.  Will
the interment take place here?

Jack.  No.  He seems to have expressed a desire to be buried in Paris.

Chasuble.  In Paris!  [Shakes his head.]  I fear that hardly points to
any very serious state of mind at the last.  You would no doubt wish me
to make some slight allusion to this tragic domestic affliction next
Sunday.  [Jack presses his hand convulsively.]  My sermon on the meaning
of the manna in the wilderness can be adapted to almost any occasion,
joyful, or, as in the present case, distressing.  [All sigh.]  I have
preached it at harvest celebrations, christenings, confirmations, on days
of humiliation and festal days.  The last time I delivered it was in the
Cathedral, as a charity sermon on behalf of the Society for the
Prevention of Discontent among the Upper Orders.  The Bishop, who was
present, was much struck by some of the analogies I drew.

Jack.  Ah! that reminds me, you mentioned christenings I think, Dr.
Chasuble?  I suppose you know how to christen all right?  [Dr. Chasuble
looks astounded.]  I mean, of course, you are continually christening,
aren't you?

Miss Prism.  It is, I regret to say, one of the Rector's most constant
duties in this parish.  I have often spoken to the poorer classes on the
subject.  But they don't seem to know what thrift is.

Chasuble.  But is there any particular infant in whom you are interested,
Mr. Worthing?  Your brother was, I believe, unmarried, was he not?

Jack.  Oh yes.

Miss Prism.  [Bitterly.]  People who live entirely for pleasure usually
are.

Jack.  But it is not for any child, dear Doctor.  I am very fond of
children.  No! the fact is, I would like to be christened myself, this
afternoon, if you have nothing better to do.

Chasuble.  But surely, Mr. Worthing, you have been christened already?

Jack.  I don't remember anything about it.

Chasuble.  But have you any grave doubts on the subject?

Jack.  I certainly intend to have.  Of course I don't know if the thing
would bother you in any way, or if you think I am a little too old now.

Chasuble.  Not at all.  The sprinkling, and, indeed, the immersion of
adults is a perfectly canonical practice.

Jack.  Immersion!

Chasuble.  You need have no apprehensions.  Sprinkling is all that is
necessary, or indeed I think advisable.  Our weather is so changeable.  At
what hour would you wish the ceremony performed?

Jack.  Oh, I might trot round about five if that would suit you.

Chasuble.  Perfectly, perfectly!  In fact I have two similar ceremonies
to perform at that time.  A case of twins that occurred recently in one
of the outlying cottages on your own estate.  Poor Jenkins the carter, a
most hard-working man.

Jack.  Oh!  I don't see much fun in being christened along with other
babies.  It would be childish.  Would half-past five do?

Chasuble.  Admirably!  Admirably!  [Takes out watch.]  And now, dear Mr.
Worthing, I will not intrude any longer into a house of sorrow.  I would
merely beg you not to be too much bowed down by grief.  What seem to us
bitter trials are often blessings in disguise.

Miss Prism.  This seems to me a blessing of an extremely obvious kind.

[Enter Cecily from the house.]

Cecily.  Uncle Jack!  Oh, I am pleased to see you back.  But what horrid
clothes you have got on!  Do go and change them.

Miss Prism.  Cecily!

Chasuble.  My child! my child!  [Cecily goes towards Jack; he kisses her
brow in a melancholy manner.]

Cecily.  What is the matter, Uncle Jack?  Do look happy!  You look as if
you had toothache, and I have got such a surprise for you.  Who do you
think is in the dining-room?  Your brother!

Jack.  Who?

Cecily.  Your brother Ernest.  He arrived about half an hour ago.

Jack.  What nonsense!  I haven't got a brother.

Cecily.  Oh, don't say that.  However badly he may have behaved to you in
the past he is still your brother.  You couldn't be so heartless as to
disown him.  I'll tell him to come out.  And you will shake hands with
him, won't you, Uncle Jack?  [Runs back into the house.]

Chasuble.  These are very joyful tidings.

Miss Prism.  After we had all been resigned to his loss, his sudden
return seems to me peculiarly distressing.

Jack.  My brother is in the dining-room?  I don't know what it all means.
I think it is perfectly absurd.

[Enter Algernon and Cecily hand in hand.  They come slowly up to Jack.]

Jack.  Good heavens!  [Motions Algernon away.]

Algernon.  Brother John, I have come down from town to tell you that I am
very sorry for all the trouble I have given you, and that I intend to
lead a better life in the future.  [Jack glares at him and does not take
his hand.]

Cecily.  Uncle Jack, you are not going to refuse your own brother's hand?

Jack.  Nothing will induce me to take his hand.  I think his coming down
here disgraceful.  He knows perfectly well why.

Cecily.  Uncle Jack, do be nice.  There is some good in every one.  Ernest
has just been telling me about his poor invalid friend Mr. Bunbury whom
he goes to visit so often.  And surely there must be much good in one who
is kind to an invalid, and leaves the pleasures of London to sit by a bed
of pain.

Jack.  Oh! he has been talking about Bunbury, has he?

Cecily.  Yes, he has told me all about poor Mr. Bunbury, and his terrible
state of health.

Jack.  Bunbury!  Well, I won't have him talk to you about Bunbury or
about anything else.  It is enough to drive one perfectly frantic.

Algernon.  Of course I admit that the faults were all on my side.  But I
must say that I think that Brother John's coldness to me is peculiarly
painful.  I expected a more enthusiastic welcome, especially considering
it is the first time I have come here.

Cecily.  Uncle Jack, if you don't shake hands with Ernest I will never
forgive you.

Jack.  Never forgive me?

Cecily.  Never, never, never!

Jack.  Well, this is the last time I shall ever do it.  [Shakes with
Algernon and glares.]

Chasuble.  It's pleasant, is it not, to see so perfect a reconciliation?
I think we might leave the two brothers together.

Miss Prism.  Cecily, you will come with us.

Cecily.  Certainly, Miss Prism.  My little task of reconciliation is
over.

Chasuble.  You have done a beautiful action to-day, dear child.

Miss Prism.  We must not be premature in our judgments.

Cecily.  I feel very happy.  [They all go off except Jack and Algernon.]

Jack.  You young scoundrel, Algy, you must get out of this place as soon
as possible.  I don't allow any Bunburying here.

[Enter Merriman.]

Merriman.  I have put Mr. Ernest's things in the room next to yours, sir.
I suppose that is all right?

Jack.  What?

Merriman.  Mr. Ernest's luggage, sir.  I have unpacked it and put it in
the room next to your own.

Jack.  His luggage?

Merriman.  Yes, sir.  Three portmanteaus, a dressing-case, two hat-boxes,
and a large luncheon-basket.

Algernon.  I am afraid I can't stay more than a week this time.

Jack.  Merriman, order the dog-cart at once.  Mr. Ernest has been
suddenly called back to town.

Merriman.  Yes, sir.  [Goes back into the house.]

Algernon.  What a fearful liar you are, Jack.  I have not been called
back to town at all.

Jack.  Yes, you have.

Algernon.  I haven't heard any one call me.

Jack.  Your duty as a gentleman calls you back.

Algernon.  My duty as a gentleman has never interfered with my pleasures
in the smallest degree.

Jack.  I can quite understand that.

Algernon.  Well, Cecily is a darling.

Jack.  You are not to talk of Miss Cardew like that.  I don't like it.

Algernon.  Well, I don't like your clothes.  You look perfectly
ridiculous in them.  Why on earth don't you go up and change?  It is
perfectly childish to be in deep mourning for a man who is actually
staying for a whole week with you in your house as a guest.  I call it
grotesque.

Jack.  You are certainly not staying with me for a whole week as a guest
or anything else.  You have got to leave . . . by the four-five train.

Algernon.  I certainly won't leave you so long as you are in mourning.  It
would be most unfriendly.  If I were in mourning you would stay with me,
I suppose.  I should think it very unkind if you didn't.

Jack.  Well, will you go if I change my clothes?

Algernon.  Yes, if you are not too long.  I never saw anybody take so
long to dress, and with such little result.

Jack.  Well, at any rate, that is better than being always over-dressed
as you are.

Algernon.  If I am occasionally a little over-dressed, I make up for it
by being always immensely over-educated.

Jack.  Your vanity is ridiculous, your conduct an outrage, and your
presence in my garden utterly absurd.  However, you have got to catch the
four-five, and I hope you will have a pleasant journey back to town.  This
Bunburying, as you call it, has not been a great success for you.

[Goes into the house.]

Algernon.  I think it has been a great success.  I'm in love with Cecily,
and that is everything.

[Enter Cecily at the back of the garden.  She picks up the can and begins
to water the flowers.]  But I must see her before I go, and make
arrangements for another Bunbury.  Ah, there she is.

Cecily.  Oh, I merely came back to water the roses.  I thought you were
with Uncle Jack.

Algernon.  He's gone to order the dog-cart for me.

Cecily.  Oh, is he going to take you for a nice drive?

Algernon.  He's going to send me away.

Cecily.  Then have we got to part?

Algernon.  I am afraid so.  It's a very painful parting.

Cecily.  It is always painful to part from people whom one has known for
a very brief space of time.  The absence of old friends one can endure
with equanimity.  But even a momentary separation from anyone to whom one
has just been introduced is almost unbearable.

Algernon.  Thank you.

[Enter Merriman.]

Merriman.  The dog-cart is at the door, sir.  [Algernon looks appealingly
at Cecily.]

Cecily.  It can wait, Merriman for . . . five minutes.

Merriman.  Yes, Miss.  [Exit Merriman.]

Algernon.  I hope, Cecily, I shall not offend you if I state quite
frankly and openly that you seem to me to be in every way the visible
personification of absolute perfection.

Cecily.  I think your frankness does you great credit, Ernest.  If you
will allow me, I will copy your remarks into my diary.  [Goes over to
table and begins writing in diary.]

Algernon.  Do you really keep a diary?  I'd give anything to look at it.
May I?

Cecily.  Oh no.  [Puts her hand over it.]  You see, it is simply a very
young girl's record of her own thoughts and impressions, and consequently
meant for publication.  When it appears in volume form I hope you will
order a copy.  But pray, Ernest, don't stop.  I delight in taking down
from dictation.  I have reached 'absolute perfection'.  You can go on.  I
am quite ready for more.

Algernon.  [Somewhat taken aback.]  Ahem!  Ahem!

Cecily.  Oh, don't cough, Ernest.  When one is dictating one should speak
fluently and not cough.  Besides, I don't know how to spell a cough.
[Writes as Algernon speaks.]

Algernon.  [Speaking very rapidly.]  Cecily, ever since I first looked
upon your wonderful and incomparable beauty, I have dared to love you
wildly, passionately, devotedly, hopelessly.

Cecily.  I don't think that you should tell me that you love me wildly,
passionately, devotedly, hopelessly.  Hopelessly doesn't seem to make
much sense, does it?

Algernon.  Cecily!

[Enter Merriman.]

Merriman.  The dog-cart is waiting, sir.

Algernon.  Tell it to come round next week, at the same hour.

Merriman.  [Looks at Cecily, who makes no sign.]  Yes, sir.

[Merriman retires.]

Cecily.  Uncle Jack would be very much annoyed if he knew you were
staying on till next week, at the same hour.

Algernon.  Oh, I don't care about Jack.  I don't care for anybody in the
whole world but you.  I love you, Cecily.  You will marry me, won't you?

Cecily.  You silly boy!  Of course.  Why, we have been engaged for the
last three months.

Algernon.  For the last three months?

Cecily.  Yes, it will be exactly three months on Thursday.

Algernon.  But how did we become engaged?

Cecily.  Well, ever since dear Uncle Jack first confessed to us that he
had a younger brother who was very wicked and bad, you of course have
formed the chief topic of conversation between myself and Miss Prism.  And
of course a man who is much talked about is always very attractive.  One
feels there must be something in him, after all.  I daresay it was
foolish of me, but I fell in love with you, Ernest.

Algernon.  Darling!  And when was the engagement actually settled?

Cecily.  On the 14th of February last.  Worn out by your entire ignorance
of my existence, I determined to end the matter one way or the other, and
after a long struggle with myself I accepted you under this dear old tree
here.  The next day I bought this little ring in your name, and this is
the little bangle with the true lover's knot I promised you always to
wear.

Algernon.  Did I give you this?  It's very pretty, isn't it?

Cecily.  Yes, you've wonderfully good taste, Ernest.  It's the excuse
I've always given for your leading such a bad life.  And this is the box
in which I keep all your dear letters.  [Kneels at table, opens box, and
produces letters tied up with blue ribbon.]

Algernon.  My letters!  But, my own sweet Cecily, I have never written
you any letters.

Cecily.  You need hardly remind me of that, Ernest.  I remember only too
well that I was forced to write your letters for you.  I wrote always
three times a week, and sometimes oftener.

Algernon.  Oh, do let me read them, Cecily?

Cecily.  Oh, I couldn't possibly.  They would make you far too conceited.
[Replaces box.]  The three you wrote me after I had broken off the
engagement are so beautiful, and so badly spelled, that even now I can
hardly read them without crying a little.

Algernon.  But was our engagement ever broken off?

Cecily.  Of course it was.  On the 22nd of last March.  You can see the
entry if you like. [Shows diary.]  'To-day I broke off my engagement with
Ernest.  I feel it is better to do so.  The weather still continues
charming.'

Algernon.  But why on earth did you break it off?  What had I done?  I
had done nothing at all.  Cecily, I am very much hurt indeed to hear you
broke it off.  Particularly when the weather was so charming.

Cecily.  It would hardly have been a really serious engagement if it
hadn't been broken off at least once.  But I forgave you before the week
was out.

Algernon.  [Crossing to her, and kneeling.]  What a perfect angel you
are, Cecily.

Cecily.  You dear romantic boy.  [He kisses her, she puts her fingers
through his hair.]  I hope your hair curls naturally, does it?

Algernon.  Yes, darling, with a little help from others.

Cecily.  I am so glad.

Algernon.  You'll never break off our engagement again, Cecily?

Cecily.  I don't think I could break it off now that I have actually met
you.  Besides, of course, there is the question of your name.

Algernon.  Yes, of course.  [Nervously.]

Cecily.  You must not laugh at me, darling, but it had always been a
girlish dream of mine to love some one whose name was Ernest.  [Algernon
rises, Cecily also.]  There is something in that name that seems to
inspire absolute confidence.  I pity any poor married woman whose husband
is not called Ernest.

Algernon.  But, my dear child, do you mean to say you could not love me
if I had some other name?

Cecily.  But what name?

Algernon.  Oh, any name you like--Algernon--for instance . . .

Cecily.  But I don't like the name of Algernon.

Algernon.  Well, my own dear, sweet, loving little darling, I really
can't see why you should object to the name of Algernon.  It is not at
all a bad name.  In fact, it is rather an aristocratic name.  Half of the
chaps who get into the Bankruptcy Court are called Algernon.  But
seriously, Cecily . . . [Moving to her] . . . if my name was Algy,
couldn't you love me?

Cecily.  [Rising.]  I might respect you, Ernest, I might admire your
character, but I fear that I should not be able to give you my undivided
attention.

Algernon.  Ahem!  Cecily!  [Picking up hat.]  Your Rector here is, I
suppose, thoroughly experienced in the practice of all the rites and
ceremonials of the Church?

Cecily.  Oh, yes.  Dr. Chasuble is a most learned man.  He has never
written a single book, so you can imagine how much he knows.

Algernon.  I must see him at once on a most important christening--I mean
on most important business.

Cecily.  Oh!

Algernon.  I shan't be away more than half an hour.

Cecily.  Considering that we have been engaged since February the 14th,
and that I only met you to-day for the first time, I think it is rather
hard that you should leave me for so long a period as half an hour.
Couldn't you make it twenty minutes?

Algernon.  I'll be back in no time.

[Kisses her and rushes down the garden.]

Cecily.  What an impetuous boy he is!  I like his hair so much.  I must
enter his proposal in my diary.

[Enter Merriman.]

Merriman.  A Miss Fairfax has just called to see Mr. Worthing.  On very
important business, Miss Fairfax states.

Cecily.  Isn't Mr. Worthing in his library?

Merriman.  Mr. Worthing went over in the direction of the Rectory some
time ago.

Cecily.  Pray ask the lady to come out here; Mr. Worthing is sure to be
back soon.  And you can bring tea.

Merriman.  Yes, Miss.  [Goes out.]

Cecily.  Miss Fairfax!  I suppose one of the many good elderly women who
are associated with Uncle Jack in some of his philanthropic work in
London.  I don't quite like women who are interested in philanthropic
work.  I think it is so forward of them.

[Enter Merriman.]

Merriman.  Miss Fairfax.

[Enter Gwendolen.]

[Exit Merriman.]

Cecily.  [Advancing to meet her.]  Pray let me introduce myself to you.
My name is Cecily Cardew.

Gwendolen.  Cecily Cardew?  [Moving to her and shaking hands.]  What a
very sweet name!  Something tells me that we are going to be great
friends.  I like you already more than I can say.  My first impressions
of people are never wrong.

Cecily.  How nice of you to like me so much after we have known each
other such a comparatively short time.  Pray sit down.

Gwendolen.  [Still standing up.]  I may call you Cecily, may I not?

Cecily.  With pleasure!

Gwendolen.  And you will always call me Gwendolen, won't you?

Cecily.  If you wish.

Gwendolen.  Then that is all quite settled, is it not?

Cecily.  I hope so.  [A pause.  They both sit down together.]

Gwendolen.  Perhaps this might be a favourable opportunity for my
mentioning who I am.  My father is Lord Bracknell.  You have never heard
of papa, I suppose?

Cecily.  I don't think so.

Gwendolen.  Outside the family circle, papa, I am glad to say, is
entirely unknown.  I think that is quite as it should be.  The home seems
to me to be the proper sphere for the man.  And certainly once a man
begins to neglect his domestic duties he becomes painfully effeminate,
does he not?  And I don't like that.  It makes men so very attractive.
Cecily, mamma, whose views on education are remarkably strict, has
brought me up to be extremely short-sighted; it is part of her system; so
do you mind my looking at you through my glasses?

Cecily.  Oh! not at all, Gwendolen.  I am very fond of being looked at.

Gwendolen.  [After examining Cecily carefully through a lorgnette.]  You
are here on a short visit, I suppose.

Cecily.  Oh no!  I live here.

Gwendolen.  [Severely.]  Really?  Your mother, no doubt, or some female
relative of advanced years, resides here also?

Cecily.  Oh no!  I have no mother, nor, in fact, any relations.

Gwendolen.  Indeed?

Cecily.  My dear guardian, with the assistance of Miss Prism, has the
arduous task of looking after me.

Gwendolen.  Your guardian?

Cecily.  Yes, I am Mr. Worthing's ward.

Gwendolen.  Oh!  It is strange he never mentioned to me that he had a
ward.  How secretive of him!  He grows more interesting hourly.  I am not
sure, however, that the news inspires me with feelings of unmixed
delight.  [Rising and going to her.]  I am very fond of you, Cecily; I
have liked you ever since I met you!  But I am bound to state that now
that I know that you are Mr. Worthing's ward, I cannot help expressing a
wish you were--well, just a little older than you seem to be--and not
quite so very alluring in appearance.  In fact, if I may speak candidly--

Cecily.  Pray do!  I think that whenever one has anything unpleasant to
say, one should always be quite candid.

Gwendolen.  Well, to speak with perfect candour, Cecily, I wish that you
were fully forty-two, and more than usually plain for your age.  Ernest
has a strong upright nature.  He is the very soul of truth and honour.
Disloyalty would be as impossible to him as deception.  But even men of
the noblest possible moral character are extremely susceptible to the
influence of the physical charms of others.  Modern, no less than Ancient
History, supplies us with many most painful examples of what I refer to.
If it were not so, indeed, History would be quite unreadable.

Cecily.  I beg your pardon, Gwendolen, did you say Ernest?

Gwendolen.  Yes.

Cecily.  Oh, but it is not Mr. Ernest Worthing who is my guardian.  It is
his brother--his elder brother.

Gwendolen.  [Sitting down again.]  Ernest never mentioned to me that he
had a brother.

Cecily.  I am sorry to say they have not been on good terms for a long
time.

Gwendolen.  Ah! that accounts for it.  And now that I think of it I have
never heard any man mention his brother.  The subject seems distasteful
to most men.  Cecily, you have lifted a load from my mind.  I was growing
almost anxious.  It would have been terrible if any cloud had come across
a friendship like ours, would it not?  Of course you are quite, quite
sure that it is not Mr. Ernest Worthing who is your guardian?

Cecily.  Quite sure.  [A pause.]  In fact, I am going to be his.

Gwendolen.  [Inquiringly.]  I beg your pardon?

Cecily.  [Rather shy and confidingly.]  Dearest Gwendolen, there is no
reason why I should make a secret of it to you.  Our little county
newspaper is sure to chronicle the fact next week.  Mr. Ernest Worthing
and I are engaged to be married.

Gwendolen.  [Quite politely, rising.]  My darling Cecily, I think there
must be some slight error.  Mr. Ernest Worthing is engaged to me.  The
announcement will appear in the _Morning Post_ on Saturday at the latest.

Cecily.  [Very politely, rising.]  I am afraid you must be under some
misconception.  Ernest proposed to me exactly ten minutes ago.  [Shows
diary.]

Gwendolen.  [Examines diary through her lorgnettte carefully.]  It is
certainly very curious, for he asked me to be his wife yesterday
afternoon at 5.30.  If you would care to verify the incident, pray do so.
[Produces diary of her own.]  I never travel without my diary.  One
should always have something sensational to read in the train.  I am so
sorry, dear Cecily, if it is any disappointment to you, but I am afraid I
have the prior claim.

Cecily.  It would distress me more than I can tell you, dear Gwendolen,
if it caused you any mental or physical anguish, but I feel bound to
point out that since Ernest proposed to you he clearly has changed his
mind.

Gwendolen.  [Meditatively.]  If the poor fellow has been entrapped into
any foolish promise I shall consider it my duty to rescue him at once,
and with a firm hand.

Cecily.  [Thoughtfully and sadly.]  Whatever unfortunate entanglement my
dear boy may have got into, I will never reproach him with it after we
are married.

Gwendolen.  Do you allude to me, Miss Cardew, as an entanglement?  You
are presumptuous.  On an occasion of this kind it becomes more than a
moral duty to speak one's mind.  It becomes a pleasure.

Cecily.  Do you suggest, Miss Fairfax, that I entrapped Ernest into an
engagement?  How dare you?  This is no time for wearing the shallow mask
of manners.  When I see a spade I call it a spade.

Gwendolen.  [Satirically.]  I am glad to say that I have never seen a
spade.  It is obvious that our social spheres have been widely different.

[Enter Merriman, followed by the footman.  He carries a salver, table
cloth, and plate stand.  Cecily is about to retort.  The presence of the
servants exercises a restraining influence, under which both girls
chafe.]

Merriman.  Shall I lay tea here as usual, Miss?

Cecily.  [Sternly, in a calm voice.]  Yes, as usual.  [Merriman begins to
clear table and lay cloth.  A long pause.  Cecily and Gwendolen glare at
each other.]

Gwendolen.  Are there many interesting walks in the vicinity, Miss
Cardew?

Cecily.  Oh! yes! a great many.  From the top of one of the hills quite
close one can see five counties.

Gwendolen.  Five counties!  I don't think I should like that; I hate
crowds.

Cecily.  [Sweetly.]  I suppose that is why you live in town?  [Gwendolen
bites her lip, and beats her foot nervously with her parasol.]

Gwendolen.  [Looking round.]  Quite a well-kept garden this is, Miss
Cardew.

Cecily.  So glad you like it, Miss Fairfax.

Gwendolen.  I had no idea there were any flowers in the country.

Cecily.  Oh, flowers are as common here, Miss Fairfax, as people are in
London.

Gwendolen.  Personally I cannot understand how anybody manages to exist
in the country, if anybody who is anybody does.  The country always bores
me to death.

Cecily.  Ah!  This is what the newspapers call agricultural depression,
is it not?  I believe the aristocracy are suffering very much from it
just at present.  It is almost an epidemic amongst them, I have been
told.  May I offer you some tea, Miss Fairfax?

Gwendolen.  [With elaborate politeness.]  Thank you.  [Aside.]  Detestable
girl!  But I require tea!

Cecily.  [Sweetly.]  Sugar?

Gwendolen.  [Superciliously.]  No, thank you.  Sugar is not fashionable
any more. [Cecily looks angrily at her, takes up the tongs and puts four
lumps of sugar into the cup.]

Cecily.  [Severely.]  Cake or bread and butter?

Gwendolen.  [In a bored manner.]  Bread and butter, please.  Cake is
rarely seen at the best houses nowadays.

Cecily.  [Cuts a very large slice of cake, and puts it on the tray.]  Hand
that to Miss Fairfax.

[Merriman does so, and goes out with footman.  Gwendolen drinks the tea
and makes a grimace.  Puts down cup at once, reaches out her hand to the
bread and butter, looks at it, and finds it is cake.  Rises in
indignation.]

Gwendolen.  You have filled my tea with lumps of sugar, and though I
asked most distinctly for bread and butter, you have given me cake.  I am
known for the gentleness of my disposition, and the extraordinary
sweetness of my nature, but I warn you, Miss Cardew, you may go too far.

Cecily.  [Rising.]  To save my poor, innocent, trusting boy from the
machinations of any other girl there are no lengths to which I would not
go.

Gwendolen.  From the moment I saw you I distrusted you.  I felt that you
were false and deceitful.  I am never deceived in such matters.  My first
impressions of people are invariably right.

Cecily.  It seems to me, Miss Fairfax, that I am trespassing on your
valuable time.  No doubt you have many other calls of a similar character
to make in the neighbourhood.

[Enter Jack.]

Gwendolen.  [Catching sight of him.]  Ernest!  My own Ernest!

Jack.  Gwendolen!  Darling!  [Offers to kiss her.]

Gwendolen.  [Draws back.]  A moment!  May I ask if you are engaged to be
married to this young lady?  [Points to Cecily.]

Jack.  [Laughing.]  To dear little Cecily!  Of course not!  What could
have put such an idea into your pretty little head?

Gwendolen.  Thank you.  You may!  [Offers her cheek.]

Cecily.  [Very sweetly.]  I knew there must be some misunderstanding,
Miss Fairfax.  The gentleman whose arm is at present round your waist is
my guardian, Mr. John Worthing.

Gwendolen.  I beg your pardon?

Cecily.  This is Uncle Jack.

Gwendolen.  [Receding.]  Jack!  Oh!

[Enter Algernon.]

Cecily.  Here is Ernest.

Algernon.  [Goes straight over to Cecily without noticing any one else.]
My own love!  [Offers to kiss her.]

Cecily.  [Drawing back.]  A moment, Ernest!  May I ask you--are you
engaged to be married to this young lady?

Algernon.  [Looking round.]  To what young lady?  Good heavens!
Gwendolen!

Cecily.  Yes! to good heavens, Gwendolen, I mean to Gwendolen.

Algernon.  [Laughing.]  Of course not!  What could have put such an idea
into your pretty little head?

Cecily.  Thank you.  [Presenting her cheek to be kissed.]  You may.
[Algernon kisses her.]

Gwendolen.  I felt there was some slight error, Miss Cardew.  The
gentleman who is now embracing you is my cousin, Mr. Algernon Moncrieff.

Cecily.  [Breaking away from Algernon.]  Algernon Moncrieff!  Oh!  [The
two girls move towards each other and put their arms round each other's
waists as if for protection.]

Cecily.  Are you called Algernon?

Algernon.  I cannot deny it.

Cecily.  Oh!

Gwendolen.  Is your name really John?

Jack.  [Standing rather proudly.]  I could deny it if I liked.  I could
deny anything if I liked.  But my name certainly is John.  It has been
John for years.

Cecily.  [To Gwendolen.]  A gross deception has been practised on both of
us.

Gwendolen.  My poor wounded Cecily!

Cecily.  My sweet wronged Gwendolen!

Gwendolen.  [Slowly and seriously.]  You will call me sister, will you
not?  [They embrace.  Jack and Algernon groan and walk up and down.]

Cecily.  [Rather brightly.]  There is just one question I would like to
be allowed to ask my guardian.

Gwendolen.  An admirable idea!  Mr. Worthing, there is just one question
I would like to be permitted to put to you.  Where is your brother
Ernest?  We are both engaged to be married to your brother Ernest, so it
is a matter of some importance to us to know where your brother Ernest is
at present.

Jack.  [Slowly and hesitatingly.]  Gwendolen--Cecily--it is very painful
for me to be forced to speak the truth.  It is the first time in my life
that I have ever been reduced to such a painful position, and I am really
quite inexperienced in doing anything of the kind.  However, I will tell
you quite frankly that I have no brother Ernest.  I have no brother at
all.  I never had a brother in my life, and I certainly have not the
smallest intention of ever having one in the future.

Cecily.  [Surprised.]  No brother at all?

Jack.  [Cheerily.]  None!

Gwendolen.  [Severely.]  Had you never a brother of any kind?

Jack.  [Pleasantly.]  Never.  Not even of any kind.

Gwendolen.  I am afraid it is quite clear, Cecily, that neither of us is
engaged to be married to any one.

Cecily.  It is not a very pleasant position for a young girl suddenly to
find herself in.  Is it?

Gwendolen.  Let us go into the house.  They will hardly venture to come
after us there.

Cecily.  No, men are so cowardly, aren't they?

[They retire into the house with scornful looks.]

Jack.  This ghastly state of things is what you call Bunburying, I
suppose?

Algernon.  Yes, and a perfectly wonderful Bunbury it is.  The most
wonderful Bunbury I have ever had in my life.

Jack.  Well, you've no right whatsoever to Bunbury here.

Algernon.  That is absurd.  One has a right to Bunbury anywhere one
chooses.  Every serious Bunburyist knows that.

Jack.  Serious Bunburyist!  Good heavens!

Algernon.  Well, one must be serious about something, if one wants to
have any amusement in life.  I happen to be serious about Bunburying.
What on earth you are serious about I haven't got the remotest idea.
About everything, I should fancy.  You have such an absolutely trivial
nature.

Jack.  Well, the only small satisfaction I have in the whole of this
wretched business is that your friend Bunbury is quite exploded.  You
won't be able to run down to the country quite so often as you used to
do, dear Algy.  And a very good thing too.

Algernon.  Your brother is a little off colour, isn't he, dear Jack?  You
won't be able to disappear to London quite so frequently as your wicked
custom was.  And not a bad thing either.

Jack.  As for your conduct towards Miss Cardew, I must say that your
taking in a sweet, simple, innocent girl like that is quite inexcusable.
To say nothing of the fact that she is my ward.

Algernon.  I can see no possible defence at all for your deceiving a
brilliant, clever, thoroughly experienced young lady like Miss Fairfax.
To say nothing of the fact that she is my cousin.

Jack.  I wanted to be engaged to Gwendolen, that is all.  I love her.

Algernon.  Well, I simply wanted to be engaged to Cecily.  I adore her.

Jack.  There is certainly no chance of your marrying Miss Cardew.

Algernon.  I don't think there is much likelihood, Jack, of you and Miss
Fairfax being united.

Jack.  Well, that is no business of yours.

Algernon.  If it was my business, I wouldn't talk about it.  [Begins to
eat muffins.]  It is very vulgar to talk about one's business.  Only
people like stock-brokers do that, and then merely at dinner parties.

Jack.  How can you sit there, calmly eating muffins when we are in this
horrible trouble, I can't make out.  You seem to me to be perfectly
heartless.

Algernon.  Well, I can't eat muffins in an agitated manner.  The butter
would probably get on my cuffs.  One should always eat muffins quite
calmly.  It is the only way to eat them.

Jack.  I say it's perfectly heartless your eating muffins at all, under
the circumstances.

Algernon.  When I am in trouble, eating is the only thing that consoles
me.  Indeed, when I am in really great trouble, as any one who knows me
intimately will tell you, I refuse everything except food and drink.  At
the present moment I am eating muffins because I am unhappy.  Besides, I
am particularly fond of muffins.  [Rising.]

Jack.  [Rising.]  Well, that is no reason why you should eat them all in
that greedy way. [Takes muffins from Algernon.]

Algernon.  [Offering tea-cake.]  I wish you would have tea-cake instead.
I don't like tea-cake.

Jack.  Good heavens!  I suppose a man may eat his own muffins in his own
garden.

Algernon.  But you have just said it was perfectly heartless to eat
muffins.

Jack.  I said it was perfectly heartless of you, under the circumstances.
That is a very different thing.

Algernon.  That may be.  But the muffins are the same.  [He seizes the
muffin-dish from Jack.]

Jack.  Algy, I wish to goodness you would go.

Algernon.  You can't possibly ask me to go without having some dinner.
It's absurd.  I never go without my dinner.  No one ever does, except
vegetarians and people like that.  Besides I have just made arrangements
with Dr. Chasuble to be christened at a quarter to six under the name of
Ernest.

Jack.  My dear fellow, the sooner you give up that nonsense the better.  I
made arrangements this morning with Dr. Chasuble to be christened myself
at 5.30, and I naturally will take the name of Ernest.  Gwendolen would
wish it.  We can't both be christened Ernest.  It's absurd.  Besides, I
have a perfect right to be christened if I like.  There is no evidence at
all that I have ever been christened by anybody.  I should think it
extremely probable I never was, and so does Dr. Chasuble.  It is entirely
different in your case.  You have been christened already.

Algernon.  Yes, but I have not been christened for years.

Jack.  Yes, but you have been christened.  That is the important thing.

Algernon.  Quite so.  So I know my constitution can stand it.  If you are
not quite sure about your ever having been christened, I must say I think
it rather dangerous your venturing on it now.  It might make you very
unwell.  You can hardly have forgotten that some one very closely
connected with you was very nearly carried off this week in Paris by a
severe chill.

Jack.  Yes, but you said yourself that a severe chill was not hereditary.

Algernon.  It usen't to be, I know--but I daresay it is now.  Science is
always making wonderful improvements in things.

Jack.  [Picking up the muffin-dish.]  Oh, that is nonsense; you are
always talking nonsense.

Algernon.  Jack, you are at the muffins again!  I wish you wouldn't.
There are only two left.  [Takes them.]  I told you I was particularly
fond of muffins.

Jack.  But I hate tea-cake.

Algernon.  Why on earth then do you allow tea-cake to be served up for
your guests?  What ideas you have of hospitality!

Jack.  Algernon!  I have already told you to go.  I don't want you here.
Why don't you go!

Algernon.  I haven't quite finished my tea yet! and there is still one
muffin left.  [Jack groans, and sinks into a chair.  Algernon still
continues eating.]

ACT DROP




THIRD ACT


SCENE


Morning-room at the Manor House.

[Gwendolen and Cecily are at the window, looking out into the garden.]

Gwendolen.  The fact that they did not follow us at once into the house,
as any one else would have done, seems to me to show that they have some
sense of shame left.

Cecily.  They have been eating muffins.  That looks like repentance.

Gwendolen.  [After a pause.]  They don't seem to notice us at all.
Couldn't you cough?

Cecily.  But I haven't got a cough.

Gwendolen.  They're looking at us.  What effrontery!

Cecily.  They're approaching.  That's very forward of them.

Gwendolen.  Let us preserve a dignified silence.

Cecily.  Certainly.  It's the only thing to do now.  [Enter Jack followed
by Algernon.  They whistle some dreadful popular air from a British
Opera.]

Gwendolen.  This dignified silence seems to produce an unpleasant effect.

Cecily.  A most distasteful one.

Gwendolen.  But we will not be the first to speak.

Cecily.  Certainly not.

Gwendolen.  Mr. Worthing, I have something very particular to ask you.
Much depends on your reply.

Cecily.  Gwendolen, your common sense is invaluable.  Mr. Moncrieff,
kindly answer me the following question.  Why did you pretend to be my
guardian's brother?

Algernon.  In order that I might have an opportunity of meeting you.

Cecily.  [To Gwendolen.]  That certainly seems a satisfactory
explanation, does it not?

Gwendolen.  Yes, dear, if you can believe him.

Cecily.  I don't.  But that does not affect the wonderful beauty of his
answer.

Gwendolen.  True.  In matters of grave importance, style, not sincerity
is the vital thing.  Mr. Worthing, what explanation can you offer to me
for pretending to have a brother?  Was it in order that you might have an
opportunity of coming up to town to see me as often as possible?

Jack.  Can you doubt it, Miss Fairfax?

Gwendolen.  I have the gravest doubts upon the subject.  But I intend to
crush them.  This is not the moment for German scepticism.  [Moving to
Cecily.]  Their explanations appear to be quite satisfactory, especially
Mr. Worthing's.  That seems to me to have the stamp of truth upon it.

Cecily.  I am more than content with what Mr. Moncrieff said.  His voice
alone inspires one with absolute credulity.

Gwendolen.  Then you think we should forgive them?

Cecily.  Yes.  I mean no.

Gwendolen.  True!  I had forgotten.  There are principles at stake that
one cannot surrender.  Which of us should tell them?  The task is not a
pleasant one.

Cecily.  Could we not both speak at the same time?

Gwendolen.  An excellent idea!  I nearly always speak at the same time as
other people.  Will you take the time from me?

Cecily.  Certainly.  [Gwendolen beats time with uplifted finger.]

Gwendolen and Cecily [Speaking together.]  Your Christian names are still
an insuperable barrier.  That is all!

Jack and Algernon [Speaking together.]  Our Christian names!  Is that
all?  But we are going to be christened this afternoon.

Gwendolen.  [To Jack.]  For my sake you are prepared to do this terrible
thing?

Jack.  I am.

Cecily.  [To Algernon.]  To please me you are ready to face this fearful
ordeal?

Algernon.  I am!

Gwendolen.  How absurd to talk of the equality of the sexes!  Where
questions of self-sacrifice are concerned, men are infinitely beyond us.

Jack.  We are.  [Clasps hands with Algernon.]

Cecily.  They have moments of physical courage of which we women know
absolutely nothing.

Gwendolen.  [To Jack.]  Darling!

Algernon.  [To Cecily.]  Darling!  [They fall into each other's arms.]

[Enter Merriman.  When he enters he coughs loudly, seeing the situation.]

Merriman.  Ahem!  Ahem!  Lady Bracknell!

Jack.  Good heavens!

[Enter Lady Bracknell.  The couples separate in alarm.  Exit Merriman.]

Lady Bracknell.  Gwendolen!  What does this mean?

Gwendolen.  Merely that I am engaged to be married to Mr. Worthing,
mamma.

Lady Bracknell.  Come here.  Sit down.  Sit down immediately.  Hesitation
of any kind is a sign of mental decay in the young, of physical weakness
in the old.  [Turns to Jack.]  Apprised, sir, of my daughter's sudden
flight by her trusty maid, whose confidence I purchased by means of a
small coin, I followed her at once by a luggage train.  Her unhappy
father is, I am glad to say, under the impression that she is attending a
more than usually lengthy lecture by the University Extension Scheme on
the Influence of a permanent income on Thought.  I do not propose to
undeceive him.  Indeed I have never undeceived him on any question.  I
would consider it wrong.  But of course, you will clearly understand that
all communication between yourself and my daughter must cease immediately
from this moment.  On this point, as indeed on all points, I am firm.

Jack.  I am engaged to be married to Gwendolen Lady Bracknell!

Lady Bracknell.  You are nothing of the kind, sir.  And now, as regards
Algernon! . . . Algernon!

Algernon.  Yes, Aunt Augusta.

Lady Bracknell.  May I ask if it is in this house that your invalid
friend Mr. Bunbury resides?

Algernon.  [Stammering.]  Oh!  No!  Bunbury doesn't live here.  Bunbury
is somewhere else at present.  In fact, Bunbury is dead.

Lady Bracknell.  Dead!  When did Mr. Bunbury die?  His death must have
been extremely sudden.

Algernon.  [Airily.]  Oh!  I killed Bunbury this afternoon.  I mean poor
Bunbury died this afternoon.

Lady Bracknell.  What did he die of?

Algernon.  Bunbury?  Oh, he was quite exploded.

Lady Bracknell.  Exploded!  Was he the victim of a revolutionary outrage?
I was not aware that Mr. Bunbury was interested in social legislation.  If
so, he is well punished for his morbidity.

Algernon.  My dear Aunt Augusta, I mean he was found out!  The doctors
found out that Bunbury could not live, that is what I mean--so Bunbury
died.

Lady Bracknell.  He seems to have had great confidence in the opinion of
his physicians.  I am glad, however, that he made up his mind at the last
to some definite course of action, and acted under proper medical advice.
And now that we have finally got rid of this Mr. Bunbury, may I ask, Mr.
Worthing, who is that young person whose hand my nephew Algernon is now
holding in what seems to me a peculiarly unnecessary manner?

Jack.  That lady is Miss Cecily Cardew, my ward.  [Lady Bracknell bows
coldly to Cecily.]

Algernon.  I am engaged to be married to Cecily, Aunt Augusta.

Lady Bracknell.  I beg your pardon?

Cecily.  Mr. Moncrieff and I are engaged to be married, Lady Bracknell.

Lady Bracknell.  [With a shiver, crossing to the sofa and sitting down.]
I do not know whether there is anything peculiarly exciting in the air of
this particular part of Hertfordshire, but the number of engagements that
go on seems to me considerably above the proper average that statistics
have laid down for our guidance.  I think some preliminary inquiry on my
part would not be out of place.  Mr. Worthing, is Miss Cardew at all
connected with any of the larger railway stations in London?  I merely
desire information.  Until yesterday I had no idea that there were any
families or persons whose origin was a Terminus.  [Jack looks perfectly
furious, but restrains himself.]

Jack.  [In a clear, cold voice.]  Miss Cardew is the grand-daughter of
the late Mr. Thomas Cardew of 149 Belgrave Square, S.W.; Gervase Park,
Dorking, Surrey; and the Sporran, Fifeshire, N.B.

Lady Bracknell.  That sounds not unsatisfactory.  Three addresses always
inspire confidence, even in tradesmen.  But what proof have I of their
authenticity?

Jack.  I have carefully preserved the Court Guides of the period.  They
are open to your inspection, Lady Bracknell.

Lady Bracknell.  [Grimly.]  I have known strange errors in that
publication.

Jack.  Miss Cardew's family solicitors are Messrs. Markby, Markby, and
Markby.

Lady Bracknell.  Markby, Markby, and Markby?  A firm of the very highest
position in their profession.  Indeed I am told that one of the Mr.
Markby's is occasionally to be seen at dinner parties.  So far I am
satisfied.

Jack.  [Very irritably.]  How extremely kind of you, Lady Bracknell!  I
have also in my possession, you will be pleased to hear, certificates of
Miss Cardew's birth, baptism, whooping cough, registration, vaccination,
confirmation, and the measles; both the German and the English variety.

Lady Bracknell.  Ah! A life crowded with incident, I see; though perhaps
somewhat too exciting for a young girl.  I am not myself in favour of
premature experiences.  [Rises, looks at her watch.]  Gwendolen! the time
approaches for our departure.  We have not a moment to lose.  As a matter
of form, Mr. Worthing, I had better ask you if Miss Cardew has any little
fortune?

Jack.  Oh! about a hundred and thirty thousand pounds in the Funds.  That
is all.  Goodbye, Lady Bracknell.  So pleased to have seen you.

Lady Bracknell.  [Sitting down again.]  A moment, Mr. Worthing.  A
hundred and thirty thousand pounds!  And in the Funds!  Miss Cardew seems
to me a most attractive young lady, now that I look at her.  Few girls of
the present day have any really solid qualities, any of the qualities
that last, and improve with time.  We live, I regret to say, in an age of
surfaces.  [To Cecily.]  Come over here, dear.  [Cecily goes across.]
Pretty child! your dress is sadly simple, and your hair seems almost as
Nature might have left it.  But we can soon alter all that.  A thoroughly
experienced French maid produces a really marvellous result in a very
brief space of time.  I remember recommending one to young Lady Lancing,
and after three months her own husband did not know her.

Jack.  And after six months nobody knew her.

Lady Bracknell.  [Glares at Jack for a few moments.  Then bends, with a
practised smile, to Cecily.]  Kindly turn round, sweet child.  [Cecily
turns completely round.]  No, the side view is what I want.  [Cecily
presents her profile.]  Yes, quite as I expected.  There are distinct
social possibilities in your profile.  The two weak points in our age are
its want of principle and its want of profile.  The chin a little higher,
dear.  Style largely depends on the way the chin is worn.  They are worn
very high, just at present.  Algernon!

Algernon.  Yes, Aunt Augusta!

Lady Bracknell.  There are distinct social possibilities in Miss Cardew's
profile.

Algernon.  Cecily is the sweetest, dearest, prettiest girl in the whole
world.  And I don't care twopence about social possibilities.

Lady Bracknell.  Never speak disrespectfully of Society, Algernon.  Only
people who can't get into it do that.  [To Cecily.]  Dear child, of
course you know that Algernon has nothing but his debts to depend upon.
But I do not approve of mercenary marriages.  When I married Lord
Bracknell I had no fortune of any kind.  But I never dreamed for a moment
of allowing that to stand in my way.  Well, I suppose I must give my
consent.

Algernon.  Thank you, Aunt Augusta.

Lady Bracknell.  Cecily, you may kiss me!

Cecily.  [Kisses her.]  Thank you, Lady Bracknell.

Lady Bracknell.  You may also address me as Aunt Augusta for the future.

Cecily.  Thank you, Aunt Augusta.

Lady Bracknell.  The marriage, I think, had better take place quite soon.

Algernon.  Thank you, Aunt Augusta.

Cecily.  Thank you, Aunt Augusta.

Lady Bracknell.  To speak frankly, I am not in favour of long
engagements.  They give people the opportunity of finding out each
other's character before marriage, which I think is never advisable.

Jack.  I beg your pardon for interrupting you, Lady Bracknell, but this
engagement is quite out of the question.  I am Miss Cardew's guardian,
and she cannot marry without my consent until she comes of age.  That
consent I absolutely decline to give.

Lady Bracknell.  Upon what grounds may I ask?  Algernon is an extremely,
I may almost say an ostentatiously, eligible young man.  He has nothing,
but he looks everything.  What more can one desire?

Jack.  It pains me very much to have to speak frankly to you, Lady
Bracknell, about your nephew, but the fact is that I do not approve at
all of his moral character.  I suspect him of being untruthful.  [Algernon
and Cecily look at him in indignant amazement.]

Lady Bracknell.  Untruthful!  My nephew Algernon?  Impossible!  He is an
Oxonian.

Jack.  I fear there can be no possible doubt about the matter.  This
afternoon during my temporary absence in London on an important question
of romance, he obtained admission to my house by means of the false
pretence of being my brother.  Under an assumed name he drank, I've just
been informed by my butler, an entire pint bottle of my Perrier-Jouet,
Brut, '89; wine I was specially reserving for myself.  Continuing his
disgraceful deception, he succeeded in the course of the afternoon in
alienating the affections of my only ward.  He subsequently stayed to
tea, and devoured every single muffin.  And what makes his conduct all
the more heartless is, that he was perfectly well aware from the first
that I have no brother, that I never had a brother, and that I don't
intend to have a brother, not even of any kind.  I distinctly told him so
myself yesterday afternoon.

Lady Bracknell.  Ahem!  Mr. Worthing, after careful consideration I have
decided entirely to overlook my nephew's conduct to you.

Jack.  That is very generous of you, Lady Bracknell.  My own decision,
however, is unalterable.  I decline to give my consent.

Lady Bracknell.  [To Cecily.]  Come here, sweet child.  [Cecily goes
over.]  How old are you, dear?

Cecily.  Well, I am really only eighteen, but I always admit to twenty
when I go to evening parties.

Lady Bracknell.  You are perfectly right in making some slight
alteration.  Indeed, no woman should ever be quite accurate about her
age.  It looks so calculating . . . [In a meditative manner.]  Eighteen,
but admitting to twenty at evening parties.  Well, it will not be very
long before you are of age and free from the restraints of tutelage.  So
I don't think your guardian's consent is, after all, a matter of any
importance.

Jack.  Pray excuse me, Lady Bracknell, for interrupting you again, but it
is only fair to tell you that according to the terms of her grandfather's
will Miss Cardew does not come legally of age till she is thirty-five.

Lady Bracknell.  That does not seem to me to be a grave objection.  Thirty-
five is a very attractive age.  London society is full of women of the
very highest birth who have, of their own free choice, remained thirty-
five for years.  Lady Dumbleton is an instance in point.  To my own
knowledge she has been thirty-five ever since she arrived at the age of
forty, which was many years ago now.  I see no reason why our dear Cecily
should not be even still more attractive at the age you mention than she
is at present.  There will be a large accumulation of property.

Cecily.  Algy, could you wait for me till I was thirty-five?

Algernon.  Of course I could, Cecily.  You know I could.

Cecily.  Yes, I felt it instinctively, but I couldn't wait all that time.
I hate waiting even five minutes for anybody.  It always makes me rather
cross.  I am not punctual myself, I know, but I do like punctuality in
others, and waiting, even to be married, is quite out of the question.

Algernon.  Then what is to be done, Cecily?

Cecily.  I don't know, Mr. Moncrieff.

Lady Bracknell.  My dear Mr. Worthing, as Miss Cardew states positively
that she cannot wait till she is thirty-five--a remark which I am bound
to say seems to me to show a somewhat impatient nature--I would be
Download .txt
gitextract_7b5xu749/

├── LICENSE
├── Makefile
├── README.md
└── src/
    ├── .gitignore
    ├── kvraft/
    │   ├── client.go
    │   ├── common.go
    │   ├── config.go
    │   ├── server.go
    │   └── test_test.go
    ├── labgob/
    │   ├── labgob.go
    │   └── test_test.go
    ├── labrpc/
    │   ├── labrpc.go
    │   └── test_test.go
    ├── linearizability/
    │   ├── bitset.go
    │   ├── linearizability.go
    │   ├── model.go
    │   └── models.go
    ├── main/
    │   ├── diskvd.go
    │   ├── ii.go
    │   ├── lockc.go
    │   ├── lockd.go
    │   ├── mr-challenge.txt
    │   ├── mr-testout.txt
    │   ├── pbc.go
    │   ├── pbd.go
    │   ├── pg-being_ernest.txt
    │   ├── pg-dorian_gray.txt
    │   ├── pg-frankenstein.txt
    │   ├── pg-grimm.txt
    │   ├── pg-huckleberry_finn.txt
    │   ├── pg-metamorphosis.txt
    │   ├── pg-sherlock_holmes.txt
    │   ├── pg-tom_sawyer.txt
    │   ├── test-ii.sh
    │   ├── test-mr.sh
    │   ├── test-wc.sh
    │   ├── viewd.go
    │   └── wc.go
    ├── mapreduce/
    │   ├── common.go
    │   ├── common_map.go
    │   ├── common_reduce.go
    │   ├── common_rpc.go
    │   ├── master.go
    │   ├── master_rpc.go
    │   ├── master_splitmerge.go
    │   ├── schedule.go
    │   ├── test_test.go
    │   └── worker.go
    ├── raft/
    │   ├── config.go
    │   ├── persister.go
    │   ├── raft.go
    │   ├── test_test.go
    │   └── util.go
    ├── shardkv/
    │   ├── client.go
    │   ├── common.go
    │   ├── config.go
    │   ├── server.go
    │   └── test_test.go
    └── shardmaster/
        ├── client.go
        ├── common.go
        ├── config.go
        ├── server.go
        └── test_test.go
Download .txt
SYMBOL INDEX (560 symbols across 46 files)

FILE: src/kvraft/client.go
  type Clerk (line 10) | type Clerk struct
    method Get (line 33) | func (ck *Clerk) Get(key string) string {
    method PutAppend (line 51) | func (ck *Clerk) PutAppend(key string, value string, op string) {
    method Put (line 72) | func (ck *Clerk) Put(key string, value string) {
    method Append (line 75) | func (ck *Clerk) Append(key string, value string) {
  function nrand (line 17) | func nrand() int64 {
  function MakeClerk (line 24) | func MakeClerk(servers []*labrpc.ClientEnd) *Clerk {

FILE: src/kvraft/common.go
  constant OK (line 4) | OK       = "OK"
  constant ErrNoKey (line 5) | ErrNoKey = "ErrNoKey"
  type Err (line 8) | type Err
  type PutAppendArgs (line 11) | type PutAppendArgs struct
  type PutAppendReply (line 19) | type PutAppendReply struct
  type GetArgs (line 24) | type GetArgs struct
  type GetReply (line 28) | type GetReply struct

FILE: src/kvraft/config.go
  function randstring (line 19) | func randstring(n int) string {
  function makeSeed (line 26) | func makeSeed() int64 {
  function random_handles (line 34) | func random_handles(kvh []*labrpc.ClientEnd) []*labrpc.ClientEnd {
  type config (line 44) | type config struct
    method checkTimeout (line 62) | func (cfg *config) checkTimeout() {
    method cleanup (line 69) | func (cfg *config) cleanup() {
    method LogSize (line 82) | func (cfg *config) LogSize() int {
    method SnapshotSize (line 94) | func (cfg *config) SnapshotSize() int {
    method connectUnlocked (line 107) | func (cfg *config) connectUnlocked(i int, to []int) {
    method connect (line 123) | func (cfg *config) connect(i int, to []int) {
    method disconnectUnlocked (line 131) | func (cfg *config) disconnectUnlocked(i int, from []int) {
    method disconnect (line 151) | func (cfg *config) disconnect(i int, from []int) {
    method All (line 157) | func (cfg *config) All() []int {
    method ConnectAll (line 165) | func (cfg *config) ConnectAll() {
    method partition (line 174) | func (cfg *config) partition(p1 []int, p2 []int) {
    method makeClient (line 191) | func (cfg *config) makeClient(to []int) *Clerk {
    method deleteClient (line 211) | func (cfg *config) deleteClient(ck *Clerk) {
    method ConnectClientUnlocked (line 223) | func (cfg *config) ConnectClientUnlocked(ck *Clerk, to []int) {
    method ConnectClient (line 232) | func (cfg *config) ConnectClient(ck *Clerk, to []int) {
    method DisconnectClientUnlocked (line 239) | func (cfg *config) DisconnectClientUnlocked(ck *Clerk, from []int) {
    method DisconnectClient (line 248) | func (cfg *config) DisconnectClient(ck *Clerk, from []int) {
    method ShutdownServer (line 255) | func (cfg *config) ShutdownServer(i int) {
    method StartServer (line 287) | func (cfg *config) StartServer(i int) {
    method Leader (line 325) | func (cfg *config) Leader() (bool, int) {
    method make_partition (line 339) | func (cfg *config) make_partition() ([]int, []int) {
    method rpcTotal (line 392) | func (cfg *config) rpcTotal() int {
    method begin (line 399) | func (cfg *config) begin(description string) {
    method op (line 406) | func (cfg *config) op() {
    method end (line 414) | func (cfg *config) end() {
  function make_config (line 360) | func make_config(t *testing.T, n int, unreliable bool, maxraftstate int)...

FILE: src/kvraft/server.go
  type Op (line 13) | type Op struct
  type KVServer (line 20) | type KVServer struct
    method println (line 34) | func (kv *KVServer) println(args ...interface{}) {
    method opt (line 40) | func (kv *KVServer) opt(client int64,msgId int64,req interface{}) (boo...
    method Get (line 60) | func (kv *KVServer) Get(req *GetArgs, reply *GetReply) {
    method PutAppend (line 68) | func (kv *KVServer) PutAppend(req *PutAppendArgs, reply *PutAppendRepl...
    method putAppend (line 73) | func (kv *KVServer) putAppend(req *PutAppendArgs) {
    method get (line 87) | func (kv *KVServer) get(args *GetArgs) (value string) {
    method Kill (line 96) | func (kv *KVServer) Kill() {
    method isRepeated (line 102) | func (kv *KVServer) isRepeated(client int64,msgId int64,update bool) b...
    method ifSaveSnapshot (line 116) | func  (kv *KVServer) ifSaveSnapshot() {
    method updateSnapshot (line 128) | func  (kv *KVServer) updateSnapshot(index int,data []byte) {
    method onApply (line 142) | func (kv *KVServer) onApply(applyMsg raft.ApplyMsg) {
    method mainLoop (line 171) | func (kv *KVServer) mainLoop() {
  function StartKVServer (line 185) | func StartKVServer(servers []*labrpc.ClientEnd, me int, persister *raft....

FILE: src/kvraft/test_test.go
  constant electionTimeout (line 16) | electionTimeout = 1 * time.Second
  constant linearizabilityCheckTimeout (line 18) | linearizabilityCheckTimeout = 1 * time.Second
  function Get (line 21) | func Get(cfg *config, ck *Clerk, key string) string {
  function Put (line 27) | func Put(cfg *config, ck *Clerk, key string, value string) {
  function Append (line 32) | func Append(cfg *config, ck *Clerk, key string, value string) {
  function check (line 37) | func check(cfg *config, t *testing.T, ck *Clerk, key string, value strin...
  function run_client (line 45) | func run_client(t *testing.T, cfg *config, me int, ca chan bool, fn func...
  function spawn_clients_and_wait (line 55) | func spawn_clients_and_wait(t *testing.T, cfg *config, ncli int, fn func...
  function NextValue (line 72) | func NextValue(prev string, val string) string {
  function checkClntAppends (line 78) | func checkClntAppends(t *testing.T, clnt int, v string, count int) {
  function checkConcurrentAppends (line 99) | func checkConcurrentAppends(t *testing.T, v string, counts []int) {
  function partitioner (line 122) | func partitioner(t *testing.T, cfg *config, ch chan bool, done *int32) {
  function GenericTest (line 151) | func GenericTest(t *testing.T, part string, nclients int, unreliable boo...
  function GenericTestLinearizability (line 285) | func GenericTestLinearizability(t *testing.T, part string, nclients int,...
  function TestBasic3A (line 426) | func TestBasic3A(t *testing.T) {
  function TestConcurrent3A (line 431) | func TestConcurrent3A(t *testing.T) {
  function TestUnreliable3A (line 436) | func TestUnreliable3A(t *testing.T) {
  function TestUnreliableOneKey3A (line 441) | func TestUnreliableOneKey3A(t *testing.T) {
  function TestOnePartition3A (line 476) | func TestOnePartition3A(t *testing.T) {
  function TestManyPartitionsOneClient3A (line 551) | func TestManyPartitionsOneClient3A(t *testing.T) {
  function TestManyPartitionsManyClients3A (line 556) | func TestManyPartitionsManyClients3A(t *testing.T) {
  function TestPersistOneClient3A (line 561) | func TestPersistOneClient3A(t *testing.T) {
  function TestPersistConcurrent3A (line 566) | func TestPersistConcurrent3A(t *testing.T) {
  function TestPersistConcurrentUnreliable3A (line 571) | func TestPersistConcurrentUnreliable3A(t *testing.T) {
  function TestPersistPartition3A (line 576) | func TestPersistPartition3A(t *testing.T) {
  function TestPersistPartitionUnreliable3A (line 581) | func TestPersistPartitionUnreliable3A(t *testing.T) {
  function TestPersistPartitionUnreliableLinearizable3A (line 586) | func TestPersistPartitionUnreliableLinearizable3A(t *testing.T) {
  function TestSnapshotRPC3B (line 597) | func TestSnapshotRPC3B(t *testing.T) {
  function TestSnapshotSize3B (line 653) | func TestSnapshotSize3B(t *testing.T) {
  function TestSnapshotRecover3B (line 684) | func TestSnapshotRecover3B(t *testing.T) {
  function TestSnapshotRecoverManyClients3B (line 689) | func TestSnapshotRecoverManyClients3B(t *testing.T) {
  function TestSnapshotUnreliable3B (line 694) | func TestSnapshotUnreliable3B(t *testing.T) {
  function TestSnapshotUnreliableRecover3B (line 699) | func TestSnapshotUnreliableRecover3B(t *testing.T) {
  function TestSnapshotUnreliableRecoverConcurrentPartition3B (line 704) | func TestSnapshotUnreliableRecoverConcurrentPartition3B(t *testing.T) {
  function TestSnapshotUnreliableRecoverConcurrentPartitionLinearizable3B (line 709) | func TestSnapshotUnreliableRecoverConcurrentPartitionLinearizable3B(t *t...

FILE: src/labgob/labgob.go
  type LabEncoder (line 22) | type LabEncoder struct
    method Encode (line 32) | func (enc *LabEncoder) Encode(e interface{}) error {
    method EncodeValue (line 37) | func (enc *LabEncoder) EncodeValue(value reflect.Value) error {
  function NewEncoder (line 26) | func NewEncoder(w io.Writer) *LabEncoder {
  type LabDecoder (line 42) | type LabDecoder struct
    method Decode (line 52) | func (dec *LabDecoder) Decode(e interface{}) error {
  function NewDecoder (line 46) | func NewDecoder(r io.Reader) *LabDecoder {
  function Register (line 58) | func Register(value interface{}) {
  function RegisterName (line 63) | func RegisterName(name string, value interface{}) {
  function checkValue (line 68) | func checkValue(value interface{}) {
  function checkType (line 72) | func checkType(t reflect.Type) {
  function checkDefault (line 122) | func checkDefault(value interface{}) {
  function checkDefault1 (line 129) | func checkDefault1(value reflect.Value, depth int, name string) {

FILE: src/labgob/test_test.go
  type T1 (line 7) | type T1 struct
  type T2 (line 14) | type T2 struct
  type T3 (line 20) | type T3 struct
  function TestGOB (line 27) | func TestGOB(t *testing.T) {
  type T4 (line 110) | type T4 struct
  function TestCapital (line 119) | func TestCapital(t *testing.T) {
  function TestDefault (line 146) | func TestDefault(t *testing.T) {

FILE: src/labrpc/labrpc.go
  type reqMsg (line 62) | type reqMsg struct
  type replyMsg (line 70) | type replyMsg struct
  type ClientEnd (line 75) | type ClientEnd struct
    method Call (line 84) | func (e *ClientEnd) Call(svcMeth string, args interface{}, reply inter...
  type Network (line 116) | type Network struct
    method Cleanup (line 156) | func (rn *Network) Cleanup() {
    method Reliable (line 160) | func (rn *Network) Reliable(yes bool) {
    method LongReordering (line 167) | func (rn *Network) LongReordering(yes bool) {
    method LongDelays (line 174) | func (rn *Network) LongDelays(yes bool) {
    method ReadEndnameInfo (line 181) | func (rn *Network) ReadEndnameInfo(endname interface{}) (enabled bool,
    method IsServerDead (line 197) | func (rn *Network) IsServerDead(endname interface{}, servername interf...
    method ProcessReq (line 207) | func (rn *Network) ProcessReq(req reqMsg) {
    method MakeEnd (line 300) | func (rn *Network) MakeEnd(endname interface{}) *ClientEnd {
    method AddServer (line 319) | func (rn *Network) AddServer(servername interface{}, rs *Server) {
    method DeleteServer (line 326) | func (rn *Network) DeleteServer(servername interface{}) {
    method Connect (line 335) | func (rn *Network) Connect(endname interface{}, servername interface{}) {
    method Enable (line 343) | func (rn *Network) Enable(endname interface{}, enabled bool) {
    method GetCount (line 351) | func (rn *Network) GetCount(servername interface{}) int {
    method GetTotalCount (line 359) | func (rn *Network) GetTotalCount() int {
  function MakeNetwork (line 130) | func MakeNetwork() *Network {
  type Server (line 369) | type Server struct
    method AddService (line 381) | func (rs *Server) AddService(svc *Service) {
    method dispatch (line 387) | func (rs *Server) dispatch(req reqMsg) replyMsg {
    method GetCount (line 414) | func (rs *Server) GetCount() int {
  function MakeServer (line 375) | func MakeServer() *Server {
  type Service (line 422) | type Service struct
    method dispatch (line 460) | func (svc *Service) dispatch(methname string, req reqMsg) replyMsg {
  function MakeService (line 429) | func MakeService(rcvr interface{}) *Service {

FILE: src/labrpc/test_test.go
  type JunkArgs (line 10) | type JunkArgs struct
  type JunkReply (line 13) | type JunkReply struct
  type JunkServer (line 17) | type JunkServer struct
    method Handler1 (line 23) | func (js *JunkServer) Handler1(args string, reply *int) {
    method Handler2 (line 30) | func (js *JunkServer) Handler2(args int, reply *string) {
    method Handler3 (line 37) | func (js *JunkServer) Handler3(args int, reply *int) {
    method Handler4 (line 45) | func (js *JunkServer) Handler4(args *JunkArgs, reply *JunkReply) {
    method Handler5 (line 50) | func (js *JunkServer) Handler5(args JunkArgs, reply *JunkReply) {
  function TestBasic (line 54) | func TestBasic(t *testing.T) {
  function TestTypes (line 89) | func TestTypes(t *testing.T) {
  function TestDisconnect (line 131) | func TestDisconnect(t *testing.T) {
  function TestCounts (line 170) | func TestCounts(t *testing.T) {
  function TestConcurrentMany (line 206) | func TestConcurrentMany(t *testing.T) {
  function TestUnreliable (line 264) | func TestUnreliable(t *testing.T) {
  function TestConcurrentOne (line 317) | func TestConcurrentOne(t *testing.T) {
  function TestRegression1 (line 379) | func TestRegression1(t *testing.T) {
  function TestKilled (line 454) | func TestKilled(t *testing.T) {
  function TestBenchmark (line 499) | func TestBenchmark(t *testing.T) {

FILE: src/linearizability/bitset.go
  type bitset (line 3) | type bitset
    method clone (line 17) | func (b bitset) clone() bitset {
    method set (line 27) | func (b bitset) set(pos uint) bitset {
    method clear (line 33) | func (b bitset) clear(pos uint) bitset {
    method get (line 39) | func (b bitset) get(pos uint) bool {
    method popcnt (line 44) | func (b bitset) popcnt() uint {
    method hash (line 56) | func (b bitset) hash() uint64 {
    method equals (line 64) | func (b bitset) equals(b2 bitset) bool {
  function newBitset (line 8) | func newBitset(bits uint) bitset {
  function bitsetIndex (line 23) | func bitsetIndex(pos uint) (uint, uint) {

FILE: src/linearizability/linearizability.go
  type entryKind (line 9) | type entryKind
  constant callEntry (line 12) | callEntry   entryKind = false
  constant returnEntry (line 13) | returnEntry           = true
  type entry (line 16) | type entry struct
  type byTime (line 23) | type byTime
    method Len (line 25) | func (a byTime) Len() int {
    method Swap (line 29) | func (a byTime) Swap(i, j int) {
    method Less (line 33) | func (a byTime) Less(i, j int) bool {
  function makeEntries (line 37) | func makeEntries(history []Operation) []entry {
  type node (line 51) | type node struct
  function insertBefore (line 59) | func insertBefore(n *node, mark *node) *node {
  function length (line 72) | func length(n *node) uint {
  function renumber (line 81) | func renumber(events []Event) []Event {
  function convertEntries (line 97) | func convertEntries(events []Event) []entry {
  function makeLinkedEntries (line 109) | func makeLinkedEntries(entries []entry) *node {
  type cacheEntry (line 128) | type cacheEntry struct
  function cacheContains (line 133) | func cacheContains(model Model, cache map[uint64][]cacheEntry, entry cac...
  type callsEntry (line 142) | type callsEntry struct
  function lift (line 147) | func lift(entry *node) {
  function unlift (line 157) | func unlift(entry *node) {
  function checkSingle (line 167) | func checkSingle(model Model, subhistory *node, kill *int32) bool {
  function fillDefault (line 216) | func fillDefault(model Model) Model {
  function CheckOperations (line 229) | func CheckOperations(model Model, history []Operation) bool {
  function CheckOperationsTimeout (line 235) | func CheckOperationsTimeout(model Model, history []Operation, timeout ti...
  function CheckEvents (line 272) | func CheckEvents(model Model, history []Event) bool {
  function CheckEventsTimeout (line 278) | func CheckEventsTimeout(model Model, history []Event, timeout time.Durat...

FILE: src/linearizability/model.go
  type Operation (line 3) | type Operation struct
  type EventKind (line 10) | type EventKind
  constant CallEvent (line 13) | CallEvent   EventKind = false
  constant ReturnEvent (line 14) | ReturnEvent EventKind = true
  type Event (line 17) | type Event struct
  type Model (line 23) | type Model struct
  function NoPartition (line 41) | func NoPartition(history []Operation) [][]Operation {
  function NoPartitionEvent (line 45) | func NoPartitionEvent(history []Event) [][]Event {
  function ShallowEqual (line 49) | func ShallowEqual(state1, state2 interface{}) bool {

FILE: src/linearizability/models.go
  type KvInput (line 5) | type KvInput struct
  type KvOutput (line 11) | type KvOutput struct
  function KvModel (line 15) | func KvModel() Model {

FILE: src/main/diskvd.go
  function usage (line 25) | func usage() {
  function main (line 30) | func main() {

FILE: src/main/ii.go
  function mapF (line 13) | func mapF(document string, value string) (res []mapreduce.KeyValue) {
  function reduceF (line 39) | func reduceF(key string, values []string) string {
  function main (line 48) | func main() {

FILE: src/main/lockc.go
  function usage (line 11) | func usage() {
  function main (line 16) | func main() {

FILE: src/main/lockd.go
  function main (line 19) | func main() {

FILE: src/main/pbc.go
  function usage (line 25) | func usage() {
  function main (line 31) | func main() {

FILE: src/main/pbd.go
  function main (line 12) | func main() {

FILE: src/main/viewd.go
  function main (line 12) | func main() {

FILE: src/main/wc.go
  function mapF (line 12) | func mapF(filename string, contents string) []mapreduce.KeyValue {
  function reduceF (line 39) | func reduceF(key string, values []string) string  {
  function main (line 56) | func main() {

FILE: src/mapreduce/common.go
  constant debugEnabled (line 9) | debugEnabled = false
  function debug (line 12) | func debug(format string, a ...interface{}) (n int, err error) {
  type jobPhase (line 20) | type jobPhase
  constant mapPhase (line 23) | mapPhase    jobPhase = "mapPhase"
  constant reducePhase (line 24) | reducePhase          = "reducePhase"
  type KeyValue (line 29) | type KeyValue struct
  function reduceName (line 36) | func reduceName(jobName string, mapTask int, reduceTask int) string {
  function mergeName (line 41) | func mergeName(jobName string, reduceTask int) string {

FILE: src/mapreduce/common_map.go
  function doMap (line 11) | func doMap(
  function ihash (line 51) | func ihash(s string) int {

FILE: src/mapreduce/common_reduce.go
  function doReduce (line 9) | func doReduce(

FILE: src/mapreduce/common_rpc.go
  type DoTaskArgs (line 13) | type DoTaskArgs struct
  type ShutdownReply (line 27) | type ShutdownReply struct
  type RegisterArgs (line 32) | type RegisterArgs struct
  function call (line 51) | func call(srv string, rpcname string,

FILE: src/mapreduce/master.go
  type Master (line 14) | type Master struct
    method Register (line 36) | func (mr *Master) Register(args *RegisterArgs, _ *struct{}) error {
    method forwardRegistrations (line 85) | func (mr *Master) forwardRegistrations(ch chan string) {
    method run (line 132) | func (mr *Master) run(jobName string, files []string, nreduce int,
    method Wait (line 155) | func (mr *Master) Wait() {
    method killWorkers (line 161) | func (mr *Master) killWorkers() []int {
  function newMaster (line 49) | func newMaster(master string) (mr *Master) {
  function Sequential (line 60) | func Sequential(jobName string, files []string, nreduce int,
  function Distributed (line 105) | func Distributed(jobName string, files []string, nreduce int, master str...

FILE: src/mapreduce/master_rpc.go
  method Shutdown (line 12) | func (mr *Master) Shutdown(_, _ *struct{}) error {
  method startRPCServer (line 21) | func (mr *Master) startRPCServer() {
  method stopRPCServer (line 59) | func (mr *Master) stopRPCServer() {

FILE: src/mapreduce/master_splitmerge.go
  method merge (line 14) | func (mr *Master) merge() {
  function removeFile (line 54) | func removeFile(n string) {
  method CleanupFiles (line 62) | func (mr *Master) CleanupFiles() {

FILE: src/mapreduce/schedule.go
  function schedule (line 17) | func schedule(jobName string, mapFiles []string, nReduce int, phase jobP...

FILE: src/mapreduce/test_test.go
  constant nNumber (line 17) | nNumber = 100000
  constant nMap (line 18) | nMap    = 20
  constant nReduce (line 19) | nReduce = 10
  function MapFunc (line 26) | func MapFunc(file string, value string) (res []KeyValue) {
  function ReduceFunc (line 37) | func ReduceFunc(key string, values []string) string {
  function check (line 46) | func check(t *testing.T, files []string) {
  function checkWorker (line 90) | func checkWorker(t *testing.T, l []int) {
  function makeInputs (line 99) | func makeInputs(num int) []string {
  function port (line 122) | func port(suffix string) string {
  function setup (line 132) | func setup() *Master {
  function cleanup (line 139) | func cleanup(mr *Master) {
  function TestSequentialSingle (line 146) | func TestSequentialSingle(t *testing.T) {
  function TestSequentialMany (line 154) | func TestSequentialMany(t *testing.T) {
  function TestParallelBasic (line 162) | func TestParallelBasic(t *testing.T) {
  function TestParallelCheck (line 174) | func TestParallelCheck(t *testing.T) {
  function TestOneFailure (line 194) | func TestOneFailure(t *testing.T) {
  function TestManyFailures (line 207) | func TestManyFailures(t *testing.T) {

FILE: src/mapreduce/worker.go
  type Parallelism (line 18) | type Parallelism struct
  type Worker (line 25) | type Worker struct
    method DoTask (line 40) | func (wk *Worker) DoTask(arg *DoTaskArgs, _ *struct{}) error {
    method Shutdown (line 98) | func (wk *Worker) Shutdown(_ *struct{}, res *ShutdownReply) error {
    method register (line 108) | func (wk *Worker) register(master string) {
  function RunWorker (line 119) | func RunWorker(MasterAddress string, me string,

FILE: src/raft/config.go
  function randstring (line 23) | func randstring(n int) string {
  function makeSeed (line 30) | func makeSeed() int64 {
  type config (line 37) | type config struct
    method crash1 (line 98) | func (cfg *config) crash1(i int) {
    method start1 (line 135) | func (cfg *config) start1(i int) {
    method checkTimeout (line 217) | func (cfg *config) checkTimeout() {
    method cleanup (line 224) | func (cfg *config) cleanup() {
    method connect (line 235) | func (cfg *config) connect(i int) {
    method disconnect (line 258) | func (cfg *config) disconnect(i int) {
    method rpcCount (line 280) | func (cfg *config) rpcCount(server int) int {
    method rpcTotal (line 284) | func (cfg *config) rpcTotal() int {
    method setunreliable (line 288) | func (cfg *config) setunreliable(unrel bool) {
    method setlongreordering (line 292) | func (cfg *config) setlongreordering(longrel bool) {
    method checkOneLeader (line 298) | func (cfg *config) checkOneLeader() int {
    method checkTerms (line 331) | func (cfg *config) checkTerms() int {
    method checkNoLeader (line 347) | func (cfg *config) checkNoLeader() {
    method nCommitted (line 359) | func (cfg *config) nCommitted(index int) (int, interface{}) {
    method wait (line 385) | func (cfg *config) wait(index int, n int, startTerm int) interface{} {
    method one (line 426) | func (cfg *config) one(cmd int, expectedServers int, retry bool) int {
    method begin (line 478) | func (cfg *config) begin(description string) {
    method end (line 490) | func (cfg *config) end() {
  function make_config (line 59) | func make_config(t *testing.T, n int, unreliable bool) *config {

FILE: src/raft/persister.go
  type Persister (line 14) | type Persister struct
    method Copy (line 24) | func (ps *Persister) Copy() *Persister {
    method SaveRaftState (line 33) | func (ps *Persister) SaveRaftState(state []byte) {
    method ReadRaftState (line 39) | func (ps *Persister) ReadRaftState() []byte {
    method RaftStateSize (line 45) | func (ps *Persister) RaftStateSize() int {
    method SaveStateAndSnapshot (line 53) | func (ps *Persister) SaveStateAndSnapshot(state []byte, snapshot []byt...
    method ReadSnapshot (line 60) | func (ps *Persister) ReadSnapshot() []byte {
    method SnapshotSize (line 66) | func (ps *Persister) SnapshotSize() int {
  function MakePersister (line 20) | func MakePersister() *Persister {

FILE: src/raft/raft.go
  constant Fallower (line 15) | Fallower, Leader, Candidate int = 1, 2, 3
  constant HeartbeatDuration (line 18) | HeartbeatDuration = time.Duration(time.Millisecond * 600)
  constant CandidateDuration (line 21) | CandidateDuration = HeartbeatDuration * 2
  type ApplyMsg (line 26) | type ApplyMsg struct
  type LogEntry (line 33) | type LogEntry struct
  type LogSnapshot (line 39) | type LogSnapshot struct
  type RequestVoteArgs (line 45) | type RequestVoteArgs struct
  type RequestVoteReply (line 53) | type RequestVoteReply struct
  type AppendEntries (line 59) | type AppendEntries struct
  type RespEntries (line 70) | type RespEntries struct
  type Raft (line 76) | type Raft struct
    method println (line 101) | func (rf *Raft) println(args ...interface{}) {
    method lock (line 107) | func (rf *Raft) lock(info string) {
    method unlock (line 112) | func (rf *Raft) unlock(info string) {
    method sendRequestVote (line 118) | func (rf *Raft) sendRequestVote(server int, args *RequestVoteArgs, rep...
    method sendAppendEnteries (line 134) | func (rf *Raft) sendAppendEnteries(server int, req *AppendEntries, res...
    method GetState (line 149) | func (rf *Raft) GetState() (int, bool) {
    method setTerm (line 157) | func (rf *Raft) setTerm(term int) {
    method addTerm (line 164) | func (rf *Raft) addTerm(term int) {
    method setStatus (line 171) | func (rf *Raft) setStatus(status int) {
    method getStatus (line 191) | func (rf *Raft) getStatus() int {
    method getCommitIndex (line 198) | func (rf *Raft) getCommitIndex() int {
    method setCommitIndex (line 205) | func (rf *Raft) setCommitIndex(index int) {
    method getLogTermAndIndex (line 212) | func (rf *Raft) getLogTermAndIndex() (int, int) {
    method getLogTermOfIndex (line 229) | func (rf *Raft) getLogTermOfIndex(index int) int {
    method getSnapshot (line 240) | func (rf *Raft) getSnapshot(index int, snapshot *LogSnapshot) int {
    method getEntriesInfo (line 251) | func (rf *Raft) getEntriesInfo(index int, snapshot *LogSnapshot,entrie...
    method getAppendEntries (line 278) | func (rf *Raft) getAppendEntries(peer int) AppendEntries {
    method incNext (line 294) | func (rf *Raft) incNext(peer int) {
    method setNext (line 303) | func (rf *Raft) setNext(peer int, next int) {
    method setNextAndMatch (line 310) | func (rf *Raft) setNextAndMatch(peer int, index int) {
    method updateLog (line 318) | func (rf *Raft) updateLog(start int, logEntrys []LogEntry,snapshot *Lo...
    method insertLog (line 348) | func (rf *Raft) insertLog(command interface{}) int {
    method updateCommitIndex (line 368) | func (rf *Raft) updateCommitIndex() bool {
    method apply (line 392) | func (rf *Raft) apply() {
    method setLastLog (line 438) | func (rf *Raft) setLastLog(req *AppendEntries) {
    method isOldRequest (line 445) | func (rf *Raft) isOldRequest(req *AppendEntries) bool {
    method resetCandidateTimer (line 457) | func (rf *Raft) resetCandidateTimer() {
    method persist (line 463) | func (rf *Raft) persist() {
    method readPersist (line 486) | func (rf *Raft) readPersist(data []byte) {
    method RequestVote (line 517) | func (rf *Raft) RequestVote(req *RequestVoteArgs, reply *RequestVoteRe...
    method Vote (line 547) | func (rf *Raft) Vote() {
    method ElectionLoop (line 600) | func (rf *Raft) ElectionLoop() {
    method RequestAppendEntries (line 624) | func (rf *Raft) RequestAppendEntries(req *AppendEntries, resp *RespEnt...
    method replicateLogTo (line 675) | func (rf *Raft) replicateLogTo(peer int) bool {
    method replicateLogNow (line 718) | func (rf *Raft) replicateLogNow() {
    method ReplicateLogLoop (line 727) | func (rf *Raft) ReplicateLogLoop(peer int) {
    method Start (line 752) | func (rf *Raft) Start(command interface{}) (index int, term int, isLea...
    method Kill (line 764) | func (rf *Raft) Kill() {
    method SaveSnapshot (line 772) | func (rf *Raft) SaveSnapshot(index int,snapshot []byte) {
  function Make (line 793) | func Make(peers []*labrpc.ClientEnd, me int,

FILE: src/raft/test_test.go
  constant RaftElectionTimeout (line 20) | RaftElectionTimeout = 1000 * time.Millisecond
  function TestInitialElection2A (line 22) | func TestInitialElection2A(t *testing.T) {
  function TestReElection2A (line 50) | func TestReElection2A(t *testing.T) {
  function TestBasicAgree2B (line 86) | func TestBasicAgree2B(t *testing.T) {
  function TestFailAgree2B (line 109) | func TestFailAgree2B(t *testing.T) {
  function TestFailNoAgree2B (line 140) | func TestFailNoAgree2B(t *testing.T) {
  function TestConcurrentStarts2B (line 191) | func TestConcurrentStarts2B(t *testing.T) {
  function TestRejoin2B (line 292) | func TestRejoin2B(t *testing.T) {
  function TestBackup2B (line 330) | func TestBackup2B(t *testing.T) {
  function TestCount2B (line 402) | func TestCount2B(t *testing.T) {
  function TestPersist12C (line 512) | func TestPersist12C(t *testing.T) {
  function TestPersist22C (line 558) | func TestPersist22C(t *testing.T) {
  function TestPersist32C (line 604) | func TestPersist32C(t *testing.T) {
  function TestFigure82C (line 644) | func TestFigure82C(t *testing.T) {
  function TestUnreliableAgree2C (line 700) | func TestUnreliableAgree2C(t *testing.T) {
  function TestFigure8Unreliable2C (line 729) | func TestFigure8Unreliable2C(t *testing.T) {
  function internalChurn (line 784) | func internalChurn(t *testing.T, unreliable bool) {
  function TestReliableChurn2C (line 929) | func TestReliableChurn2C(t *testing.T) {
  function TestUnreliableChurn2C (line 933) | func TestUnreliableChurn2C(t *testing.T) {

FILE: src/raft/util.go
  constant Debug (line 6) | Debug = 0
  function DPrintf (line 8) | func DPrintf(format string, a ...interface{}) (n int, err error) {

FILE: src/shardkv/client.go
  function key2shard (line 24) | func key2shard(key string) int {
  function nrand (line 33) | func nrand() int64 {
  type Clerk (line 40) | type Clerk struct
    method Get (line 72) | func (ck *Clerk) Get(key string) string {
    method PutAppend (line 107) | func (ck *Clerk) PutAppend(key string, value string, op string) {
    method Put (line 138) | func (ck *Clerk) Put(key string, value string) {
    method Append (line 141) | func (ck *Clerk) Append(key string, value string) {
  function MakeClerk (line 57) | func MakeClerk(masters []*labrpc.ClientEnd, make_end func(string) *labrp...

FILE: src/shardkv/common.go
  constant OK (line 15) | OK            = "OK"
  constant ErrNoKey (line 16) | ErrNoKey      = "ErrNoKey"
  constant ErrWrongGroup (line 17) | ErrWrongGroup = "ErrWrongGroup"
  type Err (line 20) | type Err
  type PutAppendArgs (line 23) | type PutAppendArgs struct
  type PutAppendReply (line 32) | type PutAppendReply struct
  type GetArgs (line 37) | type GetArgs struct
  type GetReply (line 42) | type GetReply struct
  type ReqShared (line 48) | type ReqShared struct
  type RespShared (line 53) | type RespShared struct
  type RespShareds (line 61) | type RespShareds struct
  type ReqDeleteShared (line 65) | type ReqDeleteShared struct
  type RespDeleteShared (line 70) | type RespDeleteShared struct
  function GetGroupShards (line 75) | func GetGroupShards(Shards *[shardmaster.NShards]int, group int) map[int...
  function GetGroupShardsString (line 85) | func GetGroupShardsString(shards map[int][]int) (rst string ){
  function GetServiceShardsString (line 98) | func GetServiceShardsString(kvs *[shardmaster.NShards] map[string]string...

FILE: src/shardkv/config.go
  function randstring (line 20) | func randstring(n int) string {
  function makeSeed (line 27) | func makeSeed() int64 {
  function random_handles (line 35) | func random_handles(kvh []*labrpc.ClientEnd) []*labrpc.ClientEnd {
  type group (line 45) | type group struct
  type config (line 53) | type config struct
    method checkTimeout (line 72) | func (cfg *config) checkTimeout() {
    method cleanup (line 79) | func (cfg *config) cleanup() {
    method checklogs (line 88) | func (cfg *config) checklogs() {
    method mastername (line 105) | func (cfg *config) mastername(i int) string {
    method servername (line 111) | func (cfg *config) servername(gid int, i int) string {
    method makeClient (line 115) | func (cfg *config) makeClient() *Clerk {
    method deleteClient (line 141) | func (cfg *config) deleteClient(ck *Clerk) {
    method ShutdownServer (line 153) | func (cfg *config) ShutdownServer(gi int, i int) {
    method ShutdownGroup (line 194) | func (cfg *config) ShutdownGroup(gi int) {
    method StartServer (line 201) | func (cfg *config) StartServer(gi int, i int) {
    method StartGroup (line 261) | func (cfg *config) StartGroup(gi int) {
    method StartMasterServer (line 267) | func (cfg *config) StartMasterServer(i int) {
    method shardclerk (line 289) | func (cfg *config) shardclerk() *shardmaster.Clerk {
    method join (line 303) | func (cfg *config) join(gi int) {
    method joinm (line 307) | func (cfg *config) joinm(gis []int) {
    method leave (line 321) | func (cfg *config) leave(gi int) {
    method leavem (line 325) | func (cfg *config) leavem(gis []int) {
  function make_config (line 335) | func make_config(t *testing.T, n int, unreliable bool, maxraftstate int)...

FILE: src/shardkv/server.go
  type Op (line 13) | type Op struct
  type ShardKV (line 20) | type ShardKV struct
    method println (line 47) | func (kv *ShardKV) println(args ...interface{}) {
    method isRepeated (line 53) | func (kv *ShardKV) isRepeated(client int64,msgId int64) bool {
    method cofigCompleted (line 66) | func (kv *ShardKV) cofigCompleted(Num int) bool {
    method setConfig (line 72) | func (kv *ShardKV) setConfig(config *shardmaster.Config) bool  {
    method startShard (line 82) | func (kv *ShardKV) startShard(shards *RespShareds) {
    method startConfig (line 104) | func (kv *ShardKV) startConfig(config *shardmaster.Config) {
    method isTrueGroup (line 116) | func (kv *ShardKV) isTrueGroup(shard int) bool{
    method opt (line 134) | func (kv *ShardKV) opt(req interface{}) (bool,interface{}) {
    method Get (line 151) | func (kv *ShardKV) Get(req *GetArgs, reply *GetReply) {
    method PutAppend (line 159) | func (kv *ShardKV) PutAppend(req *PutAppendArgs, reply *PutAppendReply) {
    method GetShard (line 167) | func (kv *ShardKV) GetShard(req *ReqShared, reply *RespShared) {
    method Kill (line 175) | func (kv *ShardKV) Kill() {
    method ifSaveSnapshot (line 182) | func  (kv *ShardKV) ifSaveSnapshot(save bool) {
    method updateSnapshot (line 197) | func  (kv *ShardKV) updateSnapshot(index int,data []byte) {
    method putAppend (line 217) | func (kv *ShardKV) putAppend(req *PutAppendArgs) Err {
    method get (line 237) | func (kv *ShardKV) get(req *GetArgs) (resp GetReply) {
    method onDeleteShards (line 255) | func (kv *ShardKV) onDeleteShards(req *ReqDeleteShared) {
    method DeleteShards (line 273) | func (kv *ShardKV) DeleteShards(req *ReqDeleteShared,resp *RespDeleteS...
    method deleteGroupShards (line 283) | func (kv *ShardKV) deleteGroupShards(config *shardmaster.Config,respSh...
    method onSetShard (line 301) | func (kv *ShardKV) onSetShard(resp *RespShared) {
    method onSetShards (line 328) | func (kv *ShardKV) onSetShards(resp *RespShareds) {
    method onGetShard (line 338) | func (kv *ShardKV) onGetShard(req *ReqShared) (resp RespShared) {
    method getNewShards (line 367) | func (kv *ShardKV) getNewShards() (map[int][]int,bool) {
    method onConfig (line 391) | func (kv *ShardKV) onConfig(config *shardmaster.Config) {
    method isReadyShards (line 404) | func (kv *ShardKV) isReadyShards(group int)  bool {
    method isUpdateConfig (line 415) | func (kv *ShardKV) isUpdateConfig()  (bool,map[int][]int) {
    method updateConfig (line 425) | func (kv *ShardKV) updateConfig()  {
    method onApply (line 435) | func (kv *ShardKV) onApply(applyMsg raft.ApplyMsg) {
    method mainLoop (line 470) | func (kv *ShardKV) mainLoop() {
    method isLeader (line 489) | func (kv *ShardKV) isLeader() bool  {
    method getShardFromOther (line 494) | func (kv *ShardKV) getShardFromOther(group int,shards []int,ch chan bo...
    method shardLoop (line 532) | func (kv *ShardKV) shardLoop() {
  function StartServer (line 577) | func StartServer(servers []*labrpc.ClientEnd, me int, persister *raft.Pe...

FILE: src/shardkv/test_test.go
  constant linearizabilityCheckTimeout (line 13) | linearizabilityCheckTimeout = 1 * time.Second
  function check (line 15) | func check(t *testing.T, ck *Clerk, key string, value string) {
  function TestStaticShards (line 25) | func TestStaticShards(t *testing.T) {
  function TestJoinLeave (line 89) | func TestJoinLeave(t *testing.T) {
  function TestSnapshot (line 142) | func TestSnapshot(t *testing.T) {
  function TestMissChange (line 210) | func TestMissChange(t *testing.T) {
  function TestConcurrent1 (line 296) | func TestConcurrent1(t *testing.T) {
  function TestConcurrent2 (line 377) | func TestConcurrent2(t *testing.T) {
  function TestUnreliable1 (line 448) | func TestUnreliable1(t *testing.T) {
  function TestUnreliable2 (line 490) | func TestUnreliable2(t *testing.T) {
  function TestUnreliable3 (line 553) | func TestUnreliable3(t *testing.T) {
  function TestChallenge1Delete (line 653) | func TestChallenge1Delete(t *testing.T) {
  function TestChallenge1Concurrent (line 734) | func TestChallenge1Concurrent(t *testing.T) {
  function TestChallenge2Unaffected (line 807) | func TestChallenge2Unaffected(t *testing.T) {
  function TestChallenge2Partial (line 877) | func TestChallenge2Partial(t *testing.T) {

FILE: src/shardmaster/client.go
  type Clerk (line 13) | type Clerk struct
    method Query (line 36) | func (ck *Clerk) Query(num int) Config {
    method Join (line 52) | func (ck *Clerk) Join(servers map[int][]string) {
    method Leave (line 71) | func (ck *Clerk) Leave(gids []int) {
    method Move (line 90) | func (ck *Clerk) Move(shard int, gid int) {
  function nrand (line 20) | func nrand() int64 {
  function MakeClerk (line 27) | func MakeClerk(servers []*labrpc.ClientEnd) *Clerk {

FILE: src/shardmaster/common.go
  constant NShards (line 6) | NShards = 10
  type Config (line 10) | type Config struct
  constant OK (line 17) | OK = "OK"
  type Err (line 20) | type Err
  type JoinArgs (line 22) | type JoinArgs struct
  type JoinReply (line 28) | type JoinReply struct
  type LeaveArgs (line 33) | type LeaveArgs struct
  type LeaveReply (line 39) | type LeaveReply struct
  type MoveArgs (line 44) | type MoveArgs struct
  type MoveReply (line 51) | type MoveReply struct
  type QueryArgs (line 56) | type QueryArgs struct
  type QueryReply (line 60) | type QueryReply struct
  function CopyGroups (line 67) | func CopyGroups(config *Config, groups map[int][]string) {
  function MergeGroups (line 75) | func MergeGroups(config *Config, groups map[int][]string) {
  function DeleteGroups (line 97) | func DeleteGroups(config *Config, groups []int) {
  function SortGroup (line 116) | func SortGroup(groups map[int][]string)  []int {
  function DistributionGroups (line 126) | func DistributionGroups(config *Config) {
  function GetCountGroup (line 141) | func GetCountGroup(Shards *[NShards]int, group int) (rst []int) {
  function GetCountShards (line 151) | func GetCountShards(config *Config)  map[int][]int {
  function SortCountShards (line 171) | func SortCountShards(shards map[int][]int)  []int {
  function GetMaxCountShards (line 181) | func GetMaxCountShards(config *Config)(group int,rst []int) {
  function GetMinCountShards (line 198) | func GetMinCountShards(config *Config, without int) int {
  function GetSlientInfoString (line 219) | func GetSlientInfoString(Shards []int) string {
  function GetShardsInfoString (line 231) | func GetShardsInfoString(Shards *[NShards]int) string {
  function GetShardsCountInfoString (line 243) | func GetShardsCountInfoString(config *Config) string {
  function GetGroupCountsInfoString (line 248) | func GetGroupCountsInfoString(groups map[int][]int) string {
  function GetGroupsInfoString (line 264) | func GetGroupsInfoString(groups map[int][]string) string {

FILE: src/shardmaster/config.go
  function randstring (line 16) | func randstring(n int) string {
  function random_handles (line 24) | func random_handles(kvh []*labrpc.ClientEnd) []*labrpc.ClientEnd {
  type config (line 34) | type config struct
    method checkTimeout (line 47) | func (cfg *config) checkTimeout() {
    method cleanup (line 54) | func (cfg *config) cleanup() {
    method LogSize (line 67) | func (cfg *config) LogSize() int {
    method connectUnlocked (line 80) | func (cfg *config) connectUnlocked(i int, to []int) {
    method connect (line 96) | func (cfg *config) connect(i int, to []int) {
    method disconnectUnlocked (line 104) | func (cfg *config) disconnectUnlocked(i int, from []int) {
    method disconnect (line 124) | func (cfg *config) disconnect(i int, from []int) {
    method All (line 130) | func (cfg *config) All() []int {
    method ConnectAll (line 138) | func (cfg *config) ConnectAll() {
    method partition (line 147) | func (cfg *config) partition(p1 []int, p2 []int) {
    method makeClient (line 164) | func (cfg *config) makeClient(to []int) *Clerk {
    method deleteClient (line 184) | func (cfg *config) deleteClient(ck *Clerk) {
    method ConnectClientUnlocked (line 196) | func (cfg *config) ConnectClientUnlocked(ck *Clerk, to []int) {
    method ConnectClient (line 205) | func (cfg *config) ConnectClient(ck *Clerk, to []int) {
    method DisconnectClientUnlocked (line 212) | func (cfg *config) DisconnectClientUnlocked(ck *Clerk, from []int) {
    method DisconnectClient (line 221) | func (cfg *config) DisconnectClient(ck *Clerk, from []int) {
    method ShutdownServer (line 228) | func (cfg *config) ShutdownServer(i int) {
    method StartServer (line 260) | func (cfg *config) StartServer(i int) {
    method Leader (line 299) | func (cfg *config) Leader() (bool, int) {
    method make_partition (line 313) | func (cfg *config) make_partition() ([]int, []int) {
  function make_config (line 332) | func make_config(t *testing.T, n int, unreliable bool) *config {

FILE: src/shardmaster/server.go
  type Op (line 13) | type Op struct
  type ShardMaster (line 18) | type ShardMaster struct
    method println (line 31) | func (sm *ShardMaster) println(args ...interface{}) {
    method getCurrentConfig (line 38) | func (sm *ShardMaster) getCurrentConfig() Config {
    method getConfig (line 46) | func (sm *ShardMaster) getConfig(index int, config *Config) bool {
    method appendConfig (line 57) | func (sm *ShardMaster) appendConfig(config *Config) {
    method isRepeated (line 64) | func (sm *ShardMaster) isRepeated(client int64,msgId int64,update bool...
    method opt (line 78) | func (sm *ShardMaster) opt(client int64,msgId int64,req interface{}) (...
    method Join (line 98) | func (sm *ShardMaster) Join(args *JoinArgs, reply *JoinReply) {
    method Leave (line 103) | func (sm *ShardMaster) Leave(args *LeaveArgs, reply *LeaveReply) {
    method Move (line 108) | func (sm *ShardMaster) Move(args *MoveArgs, reply *MoveReply) {
    method Query (line 113) | func (sm *ShardMaster) Query(args *QueryArgs, reply *QueryReply) {
    method Kill (line 126) | func (sm *ShardMaster) Kill() {
    method Raft (line 131) | func (sm *ShardMaster) Raft() *raft.Raft {
    method join (line 135) | func (sm *ShardMaster) join(args *JoinArgs) bool {
    method leave (line 152) | func (sm *ShardMaster) leave(args *LeaveArgs) bool {
    method move (line 164) | func (sm *ShardMaster) move(args *MoveArgs,) bool{
    method query (line 176) | func (sm *ShardMaster) query(args *QueryArgs) Config {
    method onApply (line 183) | func (sm *ShardMaster)onApply(applyMsg raft.ApplyMsg) {
    method mainLoop (line 205) | func (sm *ShardMaster)  mainLoop() {
  function StartServer (line 220) | func StartServer(servers []*labrpc.ClientEnd, me int, persister *raft.Pe...

FILE: src/shardmaster/test_test.go
  function check (line 11) | func check(t *testing.T, groups []int, ck *Clerk) {
  function check_same_config (line 55) | func check_same_config(t *testing.T, c1 Config, c2 Config) {
  function TestBasic (line 80) | func TestBasic(t *testing.T) {
  function TestMulti (line 252) | func TestMulti(t *testing.T) {
Condensed preview — 63 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (3,660K chars).
[
  {
    "path": "LICENSE",
    "chars": 1061,
    "preview": "MIT License\n\nCopyright (c) 2019 莫失莫忘\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof th"
  },
  {
    "path": "Makefile",
    "chars": 2001,
    "preview": "# This is the Makefile helping you submit the labs.  \n# Just create 6.824/api.key with your API key in it, \n# and submit"
  },
  {
    "path": "README.md",
    "chars": 206,
    "preview": "# MIT-6.824-2018\nhttps://pdos.csail.mit.edu/6.824/\n\n## Status\n- [x] MapReduce\n- [x] Raft\n- [x] Raft K/V Service\n- [x] Sh"
  },
  {
    "path": "src/.gitignore",
    "chars": 95,
    "preview": "*.*/\nmrtmp.*\n824-mrinput-*.txt\n/main/diff.out\n/mapreduce/x.txt\n/pbservice/x.txt\n/kvpaxos/x.txt\n"
  },
  {
    "path": "src/kvraft/client.go",
    "chars": 1622,
    "preview": "package raftkv\n\nimport \"labrpc\"\nimport \"crypto/rand\"\nimport \"math/big\"\nimport \"time\"\nimport \"sync/atomic\"\nimport \"log\"\n\n"
  },
  {
    "path": "src/kvraft/common.go",
    "chars": 405,
    "preview": "package raftkv\n\nconst (\n\tOK       = \"OK\"\n\tErrNoKey = \"ErrNoKey\"\n)\n\ntype Err string\n\n// Put or Append\ntype PutAppendArgs "
  },
  {
    "path": "src/kvraft/config.go",
    "chars": 10106,
    "preview": "package raftkv\n\nimport \"labrpc\"\nimport \"testing\"\nimport \"os\"\n\n// import \"log\"\nimport crand \"crypto/rand\"\nimport \"math/bi"
  },
  {
    "path": "src/kvraft/server.go",
    "chars": 4465,
    "preview": "package raftkv\n\nimport (\n\t\"labgob\"\n\t\"labrpc\"\n\t\"log\"\n\t\"raft\"\n\t\"sync\"\n\t\"time\"\n\t\"bytes\"\n)\n\ntype Op struct {\n\tCh  chan (inte"
  },
  {
    "path": "src/kvraft/test_test.go",
    "chars": 19820,
    "preview": "package raftkv\n\nimport \"linearizability\"\n\nimport \"testing\"\nimport \"strconv\"\nimport \"time\"\nimport \"math/rand\"\nimport \"log"
  },
  {
    "path": "src/labgob/labgob.go",
    "chars": 3822,
    "preview": "package labgob\n\n//\n// trying to send non-capitalized fields over RPC produces a range of\n// misbehavior, including both "
  },
  {
    "path": "src/labgob/test_test.go",
    "chars": 2999,
    "preview": "package labgob\n\nimport \"testing\"\n\nimport \"bytes\"\n\ntype T1 struct {\n\tT1int0    int\n\tT1int1    int\n\tT1string0 string\n\tT1st"
  },
  {
    "path": "src/labrpc/labrpc.go",
    "chars": 13297,
    "preview": "package labrpc\n\n//\n// channel-based RPC, for 824 labs.\n//\n// simulates a network that can lose requests, lose replies,\n/"
  },
  {
    "path": "src/labrpc/test_test.go",
    "chars": 9822,
    "preview": "package labrpc\n\nimport \"testing\"\nimport \"strconv\"\nimport \"sync\"\nimport \"runtime\"\nimport \"time\"\nimport \"fmt\"\n\ntype JunkAr"
  },
  {
    "path": "src/linearizability/bitset.go",
    "chars": 1425,
    "preview": "package linearizability\n\ntype bitset []uint64\n\n// data layout:\n// bits 0-63 are in data[0], the next are in data[1], etc"
  },
  {
    "path": "src/linearizability/linearizability.go",
    "chars": 6643,
    "preview": "package linearizability\n\nimport (\n\t\"sort\"\n\t\"sync/atomic\"\n\t\"time\"\n)\n\ntype entryKind bool\n\nconst (\n\tcallEntry   entryKind "
  },
  {
    "path": "src/linearizability/model.go",
    "chars": 1451,
    "preview": "package linearizability\n\ntype Operation struct {\n\tInput  interface{}\n\tCall   int64 // invocation time\n\tOutput interface{"
  },
  {
    "path": "src/linearizability/models.go",
    "chars": 1339,
    "preview": "package linearizability\n\n// kv model\n\ntype KvInput struct {\n\tOp uint8 // 0 => get, 1 => put, 2 => append\n\tKey string\n\tVa"
  },
  {
    "path": "src/main/diskvd.go",
    "chars": 1790,
    "preview": "package main\n\n//\n// start a diskvd server. it's a member of some replica\n// group, which has other members, and it needs"
  },
  {
    "path": "src/main/ii.go",
    "chars": 1864,
    "preview": "package main\n\nimport \"os\"\nimport \"fmt\"\nimport \"mapreduce\"\nimport \"strings\"\nimport \"unicode\"\nimport \"strconv\"\n// The mapp"
  },
  {
    "path": "src/main/lockc.go",
    "chars": 500,
    "preview": "package main\n\n//\n// see comments in lockd.go\n//\n\nimport \"lockservice\"\nimport \"os\"\nimport \"fmt\"\n\nfunc usage() {\n\tfmt.Prin"
  },
  {
    "path": "src/main/lockd.go",
    "chars": 657,
    "preview": "package main\n\n// export GOPATH=~/6.824\n// go build lockd.go\n// go build lockc.go\n// ./lockd -p a b &\n// ./lockd -b a b &"
  },
  {
    "path": "src/main/mr-challenge.txt",
    "chars": 1667,
    "preview": "www: 8 pg-being_ernest.txt,pg-dorian_gray.txt,pg-frankenstein.txt,pg-grimm.txt,pg-huckleberry_finn.txt,pg-metamorphosis."
  },
  {
    "path": "src/main/mr-testout.txt",
    "chars": 99,
    "preview": "that: 7871\nit: 7987\nin: 8415\nwas: 8578\na: 13382\nof: 13536\nI: 14296\nto: 16079\nand: 23612\nthe: 29748\n"
  },
  {
    "path": "src/main/pbc.go",
    "chars": 875,
    "preview": "package main\n\n//\n// pbservice client application\n//\n// export GOPATH=~/6.824\n// go build viewd.go\n// go build pbd.go\n// "
  },
  {
    "path": "src/main/pbd.go",
    "chars": 300,
    "preview": "package main\n\n//\n// see directions in pbc.go\n//\n\nimport \"time\"\nimport \"pbservice\"\nimport \"os\"\nimport \"fmt\"\n\nfunc main() "
  },
  {
    "path": "src/main/pg-being_ernest.txt",
    "chars": 138885,
    "preview": "The Project Gutenberg eBook, The Importance of Being Earnest, by Oscar\nWilde\n\n\nThis eBook is for the use of anyone anywh"
  },
  {
    "path": "src/main/pg-dorian_gray.txt",
    "chars": 453168,
    "preview": "The Project Gutenberg EBook of The Picture of Dorian Gray, by Oscar Wilde\n\nThis eBook is for the use of anyone anywhere "
  },
  {
    "path": "src/main/pg-frankenstein.txt",
    "chars": 441033,
    "preview": "Project Gutenberg's Frankenstein, by Mary Wollstonecraft (Godwin) Shelley\n\nThis eBook is for the use of anyone anywhere "
  },
  {
    "path": "src/main/pg-grimm.txt",
    "chars": 540174,
    "preview": "The Project Gutenberg EBook of Grimms' Fairy Tales, by The Brothers Grimm\n\nThis eBook is for the use of anyone anywhere "
  },
  {
    "path": "src/main/pg-huckleberry_finn.txt",
    "chars": 594262,
    "preview": "\n\nThe Project Gutenberg EBook of Adventures of Huckleberry Finn, Complete\nby Mark Twain (Samuel Clemens)\n\nThis eBook is "
  },
  {
    "path": "src/main/pg-metamorphosis.txt",
    "chars": 139054,
    "preview": "The Project Gutenberg EBook of Metamorphosis, by Franz Kafka\nTranslated by David Wyllie.\n\nThis eBook is for the use of a"
  },
  {
    "path": "src/main/pg-sherlock_holmes.txt",
    "chars": 581863,
    "preview": "Project Gutenberg's The Adventures of Sherlock Holmes, by Arthur Conan Doyle\n\nThis eBook is for the use of anyone anywhe"
  },
  {
    "path": "src/main/pg-tom_sawyer.txt",
    "chars": 412665,
    "preview": "\nThe Project Gutenberg EBook of The Adventures of Tom Sawyer, Complete by\nMark Twain (Samuel Clemens)\n\nThis eBook is for"
  },
  {
    "path": "src/main/test-ii.sh",
    "chars": 468,
    "preview": "#!/bin/bash\ngo run ii.go master sequential pg-*.txt\n\n# cause sort to be case sensitive.\n# on Ubuntu (Athena) it's otherw"
  },
  {
    "path": "src/main/test-mr.sh",
    "chars": 491,
    "preview": "#!/bin/bash\nhere=$(dirname \"$0\")\n[[ \"$here\" = /* ]] || here=\"$PWD/$here\"\nexport GOPATH=\"$here/../../\"\necho \"\"\necho \"==> "
  },
  {
    "path": "src/main/test-wc.sh",
    "chars": 326,
    "preview": "#!/bin/bash\ngo run wc.go master sequential pg-*.txt\nsort -n -k2 mrtmp.wcseq | tail -10 | diff - mr-testout.txt > diff.ou"
  },
  {
    "path": "src/main/viewd.go",
    "chars": 283,
    "preview": "package main\n\n//\n// see directions in pbc.go\n//\n\nimport \"time\"\nimport \"viewservice\"\nimport \"os\"\nimport \"fmt\"\n\nfunc main("
  },
  {
    "path": "src/main/wc.go",
    "chars": 1515,
    "preview": "package main\n\nimport (\n\t\"fmt\"\n\t\"mapreduce\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\t\"unicode\"\n)\n\nfunc mapF(filename string, contents"
  },
  {
    "path": "src/mapreduce/common.go",
    "chars": 1108,
    "preview": "package mapreduce\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n)\n\n// Debugging enabled?\nconst debugEnabled = false\n\n// debug() will only "
  },
  {
    "path": "src/mapreduce/common_map.go",
    "chars": 1029,
    "preview": "package mapreduce\n\nimport (\n\t\"encoding/json\"\n\t\"hash/fnv\"\n\t\"io/ioutil\"\n\t\"log\"\n\t\"os\"\n)\n\nfunc doMap(\n\tjobName string, // th"
  },
  {
    "path": "src/mapreduce/common_reduce.go",
    "chars": 1053,
    "preview": "package mapreduce\n\nimport (\n\t\"encoding/json\"\n\t\"log\"\n\t\"os\"\n)\n\nfunc doReduce(\n\tjobName string, // the name of the whole Ma"
  },
  {
    "path": "src/mapreduce/common_rpc.go",
    "chars": 1929,
    "preview": "package mapreduce\n\nimport (\n\t\"fmt\"\n\t\"net/rpc\"\n)\n\n// What follows are RPC types and methods.\n// Field names must start wi"
  },
  {
    "path": "src/mapreduce/master.go",
    "chars": 4906,
    "preview": "package mapreduce\n\n//\n// Please do not modify this file.\n//\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"sync\"\n)\n\n// Master holds all the s"
  },
  {
    "path": "src/mapreduce/master_rpc.go",
    "chars": 1574,
    "preview": "package mapreduce\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"net\"\n\t\"net/rpc\"\n\t\"os\"\n)\n\n// Shutdown is an RPC method that shuts down the Ma"
  },
  {
    "path": "src/mapreduce/master_splitmerge.go",
    "chars": 1447,
    "preview": "package mapreduce\n\nimport (\n\t\"bufio\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"sort\"\n)\n\n// merge combines the results of th"
  },
  {
    "path": "src/mapreduce/schedule.go",
    "chars": 1543,
    "preview": "package mapreduce\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n)\n\n//\n// schedule() starts and waits for all tasks in the given phase (mapPha"
  },
  {
    "path": "src/mapreduce/test_test.go",
    "chars": 4756,
    "preview": "package mapreduce\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"bufio\"\n\t\"log\"\n\t\"os\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n)\n\nconst (\n\tn"
  },
  {
    "path": "src/mapreduce/worker.go",
    "chars": 3722,
    "preview": "package mapreduce\n\n//\n// Please do not modify this file.\n//\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"net\"\n\t\"net/rpc\"\n\t\"os\"\n\t\"sync\"\n\t\"ti"
  },
  {
    "path": "src/raft/config.go",
    "chars": 12183,
    "preview": "package raft\n\n//\n// support for Raft tester.\n//\n// we will use the original config.go to test your code for grading.\n// "
  },
  {
    "path": "src/raft/persister.go",
    "chars": 1438,
    "preview": "package raft\n\n//\n// support for Raft and kvraft to save persistent\n// Raft state (log &c) and k/v server snapshots.\n//\n/"
  },
  {
    "path": "src/raft/raft.go",
    "chars": 19787,
    "preview": "package raft\n\nimport \"sync\"\nimport \"labrpc\"\nimport \"time\"\nimport \"math/rand\"\nimport \"log\"\nimport \"bytes\"\nimport \"labgob\""
  },
  {
    "path": "src/raft/test_test.go",
    "chars": 19639,
    "preview": "package raft\n\n//\n// Raft tests.\n//\n// we will use the original test_test.go to test your code for grading.\n// so, while "
  },
  {
    "path": "src/raft/util.go",
    "chars": 181,
    "preview": "package raft\n\nimport \"log\"\n\n// Debugging\nconst Debug = 0\n\nfunc DPrintf(format string, a ...interface{}) (n int, err erro"
  },
  {
    "path": "src/shardkv/client.go",
    "chars": 3261,
    "preview": "package shardkv\n\n//\n// client code to talk to a sharded key/value service.\n//\n// the client first talks to the shardmast"
  },
  {
    "path": "src/shardkv/common.go",
    "chars": 1828,
    "preview": "package shardkv\n\nimport \"shardmaster\"\nimport \"strconv\"\n//\n// Sharded key/value server.\n// Lots of replica groups, each r"
  },
  {
    "path": "src/shardkv/config.go",
    "chars": 9333,
    "preview": "package shardkv\n\nimport \"shardmaster\"\nimport \"labrpc\"\nimport \"testing\"\nimport \"os\"\n\n// import \"log\"\nimport crand \"crypto"
  },
  {
    "path": "src/shardkv/server.go",
    "chars": 15271,
    "preview": "package shardkv\n\nimport \"labrpc\"\nimport \"raft\"\nimport \"sync\"\nimport \"labgob\"\nimport \"log\"\nimport \"time\"\nimport \"bytes\"\ni"
  },
  {
    "path": "src/shardkv/test_test.go",
    "chars": 18480,
    "preview": "package shardkv\n\nimport \"linearizability\"\n\nimport \"testing\"\nimport \"strconv\"\nimport \"time\"\nimport \"fmt\"\nimport \"sync/ato"
  },
  {
    "path": "src/shardmaster/client.go",
    "chars": 2031,
    "preview": "package shardmaster\n\n//\n// Shardmaster clerk.\n//\n\nimport \"labrpc\"\nimport \"time\"\nimport \"crypto/rand\"\nimport \"math/big\"\ni"
  },
  {
    "path": "src/shardmaster/common.go",
    "chars": 4937,
    "preview": "package shardmaster\n\nimport \"strconv\"\nimport \"sort\"\n\nconst NShards = 10\n\n// A configuration -- an assignment of shards t"
  },
  {
    "path": "src/shardmaster/config.go",
    "chars": 8232,
    "preview": "package shardmaster\n\nimport \"labrpc\"\nimport \"raft\"\nimport \"testing\"\nimport \"os\"\n\n// import \"log\"\nimport crand \"crypto/ra"
  },
  {
    "path": "src/shardmaster/server.go",
    "chars": 5471,
    "preview": "package shardmaster\n\n\nimport \"raft\"\nimport \"labrpc\"\nimport \"sync\"\nimport \"labgob\"\nimport \"time\"\nimport \"log\"\n\nvar smOnce"
  },
  {
    "path": "src/shardmaster/test_test.go",
    "chars": 8446,
    "preview": "package shardmaster\n\nimport (\n\t\"sync\"\n\t\"testing\"\n)\n\n// import \"time\"\nimport \"fmt\"\n\nfunc check(t *testing.T, groups []int"
  }
]

About this extraction

This page contains the full source code of the wlgq2/MIT-6.824-2018 GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 63 files (3.4 MB), approximately 889.3k tokens, and a symbol index with 560 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!