Example #1
0
// Construct a new RaftLock.
//
// It is expected that raft.ConsensusModule.Start() will be called later using the
// returned RaftLock as the raft.ChangeListener parameter.
//
func NewRaftLock(
	raftICMAC ICM_AppendCommand,
	raftLog raft.LogReadOnly,
	initialLocks []string,
	initialCommitIndex raft.LogIndex,
) *RaftLock {

	// TODO: copy initial state
	rl := &RaftLock{
		raftICMAC,
		raftLog,
		statemachine.NewInMemoryLSM(),
		statemachine.NewInMemoryLSM(),
		initialCommitIndex,
		initialCommitIndex,
		nil, // commitApplier
		make(map[raft.LogIndex]chan struct{}),
	}

	applyLocks(initialLocks, rl.committedLocks)
	applyLocks(initialLocks, rl.uncommittedLocks)

	// Start commitApplier goroutine
	rl.commitApplier = runner.NewTriggeredRunner(rl.applyPendingCommits)

	return rl
}
Example #2
0
func TestTriggeredRunner(t *testing.T) {
	fRunning := false
	fRunCount := 0
	f := func() {
		fRunning = true
		time.Sleep(20 * time.Millisecond)
		fRunning = false
		fRunCount++
	}

	tr := runner.NewTriggeredRunner(f)
	if fRunning || fRunCount != 0 {
		t.Fatal()
	}

	// No first run without trigger
	time.Sleep(10 * time.Millisecond)
	if fRunning || fRunCount != 0 {
		t.Fatal()
	}

	// TriggerRun should run the function
	tr.TriggerRun() // Run #1
	time.Sleep(10 * time.Millisecond)
	if !fRunning {
		t.Fatal()
	}
	time.Sleep(20 * time.Millisecond)
	if fRunCount != 1 {
		t.Fatal()
	}

	// Extra TriggerRuns should return immediately and collapse into 1 run
	tr.TriggerRun() // Run #2
	time.Sleep(10 * time.Millisecond)
	if !fRunning {
		t.Fatal()
	}
	tr.TriggerRun() // Run #3
	tr.TriggerRun() // should be collapsed into pending run #3
	tr.TriggerRun() // should be collapsed into pending run #3
	time.Sleep(20 * time.Millisecond)
	if fRunCount != 2 {
		t.Fatal()
	}
	if !fRunning {
		t.Fatal()
	}
	time.Sleep(20 * time.Millisecond)
	if fRunning || fRunCount != 3 {
		t.Fatal()
	}

	// StopSync waits for current run to complete
	tr.TriggerRun() // Run #4
	time.Sleep(10 * time.Millisecond)
	if !fRunning {
		t.Fatal()
	}
	tr.StopSync()
	if fRunning || fRunCount != 4 {
		t.Fatal()
	}

	// TriggerRun & StopSync should now panic
	test_ExpectPanic(t, tr.TriggerRun, "send on closed channel")
	test_ExpectPanic(t, tr.StopSync, "close of closed channel")

	// TestHelperFakeRestart & TestHelperRunOnceIfTriggerPending
	tr.TestHelperFakeRestart()
	if tr.TestHelperRunOnceIfTriggerPending() {
		t.Fatal()
	}
	tr.TriggerRun() // Run #5
	time.Sleep(10 * time.Millisecond)
	if fRunning || fRunCount != 4 {
		t.Fatal()
	}
	if !tr.TestHelperRunOnceIfTriggerPending() {
		t.Fatal()
	}
	if fRunning || fRunCount != 5 {
		t.Fatal()
	}
}