예제 #1
0
파일: lock_impl.go 프로젝트: divtxt/lockd
// Implementation of locking.LockApi
func NewLockApiImpl() (*raftlock.RaftLock, error) {

	// --  Prepare raft ConsensusModule parameters

	raftPersistentState := raft_rps.NewIMPSWithCurrentTerm(0)

	raftLog := raft_log.NewInMemoryLog()

	timeSettings := raft_config.TimeSettings{TickerDuration, ElectionTimeoutLow}

	clusterInfo, err := raft_config.NewClusterInfo([]raft.ServerId{"_SOLO_"}, "_SOLO_")
	if err != nil {
		return nil, err
	}

	// -- Create the raft ConsensusModule
	raftCm, err := raft_impl.NewConsensusModule(
		raftPersistentState,
		raftLog,
		nil, // should not actually need RpcService for single-node
		clusterInfo,
		MaxEntriesPerAppendEntry,
		timeSettings,
	)
	if err != nil {
		return nil, err
	}

	// -- Make the LockApi

	raftLock := raftlock.NewRaftLock(
		raftCm,
		raftLog,
		[]string{}, // no initial locks
		0,          // initialCommitIndex
	)

	raftCm.Start(raftLock)

	return raftLock, nil
}
예제 #2
0
func TestRaftLock(t *testing.T) {
	var raftLog raft.Log = raft_log.NewInMemoryLog()
	for logIndex := 1; logIndex <= 101; logIndex++ {
		entry := raft.LogEntry{raft.TermNo(logIndex / 10), []byte{}}
		raftLog.AppendEntry(entry)
	}
	iole, err := raftLog.GetIndexOfLastEntry()
	if err != nil {
		t.Fatal(err)
	}
	if iole != 101 {
		t.Fatal(iole)
	}

	raftICMAC := &Simple_ICM_AppendCommand{raftLog, 11}

	rl := raftlock.NewRaftLock(
		raftICMAC,
		raftLog,
		[]string{"bar"},
		101,
	)
	rlCommitApplier := rl.TestHelperGetCommitApplier()
	rlCommitApplier.StopSync()
	rlCommitApplier.TestHelperFakeRestart()

	checkLockState := func(name string, ecs bool, eucs bool) {
		cs, ucs := rl.IsLocked(name)
		if cs != ecs || ucs != eucs {
			t.Fatalf("IsLocked(\"%v\") = (%v, %v) but expected (%v, %v)", name, cs, ucs, ecs, eucs)
		}
	}

	// check starting states
	checkLockState("foo", false, false)
	checkLockState("bar", true, true)

	// unlock "foo" should return nil to indicate unlock failure
	if rl.Unlock("foo") != nil {
		t.Fatal()
	}
	checkLockState("foo", false, false)

	// Lock "foo"
	lockFooCommitChan := rl.Lock("foo")
	if lockFooCommitChan == nil {
		t.Fatal()
	}
	chanWillBlock(t, lockFooCommitChan)
	checkLockState("foo", false, true)

	// a second lock "foo" should return nil to indicate lock failure
	if rl.Lock("foo") != nil {
		t.Fatal()
	}
	checkLockState("foo", false, true)

	// lock "bar" should return nil to indicate lock failure
	if rl.Lock("bar") != nil {
		t.Fatal()
	}
	checkLockState("bar", true, true)

	// Unlock "bar"
	unlockBarCommitChan := rl.Unlock("bar")
	if unlockBarCommitChan == nil {
		t.Fatal()
	}
	chanWillBlock(t, unlockBarCommitChan)
	checkLockState("bar", true, false)

	// Advance commitIndex by 1 log entry
	if rlCommitApplier.TestHelperRunOnceIfTriggerPending() {
		t.Fatal()
	}
	rl.CommitIndexChanged(102)
	if !rlCommitApplier.TestHelperRunOnceIfTriggerPending() {
		t.Fatal()
	}
	checkLockState("foo", true, true)
	checkLockState("bar", true, false) // FAIL
	chanHasValue(t, lockFooCommitChan)
	chanWillBlock(t, unlockBarCommitChan)

	// Relock "bar"
	relockBarCommitChan := rl.Lock("bar")
	if relockBarCommitChan == nil {
		t.Fatal()
	}
	checkLockState("bar", true, true)
	chanWillBlock(t, relockBarCommitChan)

	// Advance commitIndex by 2 log entries
	rl.CommitIndexChanged(104)
	if !rlCommitApplier.TestHelperRunOnceIfTriggerPending() {
		t.Fatal()
	}
	checkLockState("foo", true, true)
	checkLockState("bar", true, true)
	chanHasValue(t, unlockBarCommitChan)
	chanHasValue(t, relockBarCommitChan)
}