From 90c29829e85e2ffbcc90d08d9b78121a32a47a20 Mon Sep 17 00:00:00 2001 From: Svarog Date: Mon, 31 Dec 2018 12:17:55 +0200 Subject: [PATCH] [DEV-328] Added test to fully cover store.blockFile() in single-cpu applications (#138) --- database/ffldb/blockio_test.go | 57 ++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/database/ffldb/blockio_test.go b/database/ffldb/blockio_test.go index 4fec52b77..0da53dc41 100644 --- a/database/ffldb/blockio_test.go +++ b/database/ffldb/blockio_test.go @@ -1,8 +1,10 @@ package ffldb import ( + "container/list" "errors" "os" + "sync" "testing" "bou.ke/monkey" @@ -114,3 +116,58 @@ func TestHandleRollbackErrors(t *testing.T) { }() } } + +// TestBlockFileSingleThread tests a certain branch of blockStore.blockFile() that never gets hit in +// computers with a single CPU, since the number of goroutines is determined by number of CPUs. +func TestBlockFileSingleCPU(t *testing.T) { + pdb := newTestDb("TestBlockFileSingleCPU", t) + defer pdb.Close() + + // Write empty block to database, so that 0 file is created + _, err := pdb.store.writeBlock([]byte{}) + if err != nil { + t.Fatalf("TestBlockFileSingleCPU: Error writing block: %s", err) + } + // Close the file, and clear the openBlocksLRU + pdb.store.writeCursor.curFile.file.Close() + pdb.store.writeCursor.curFile.file = nil + pdb.store.openBlocksLRU = &list.List{} + + blockFileCompleteChan := make(chan bool) + runlockedChan := make(chan bool) + + // patch RLocks so that they don't interfere + patchRLock := monkey.Patch((*sync.RWMutex).RLock, func(*sync.RWMutex) {}) + defer patchRLock.Unpatch() + + // patch RUnlocks to know where are we standing in the execution of blockFile() + patchRUnlock := monkey.Patch((*sync.RWMutex).RUnlock, func(mutex *sync.RWMutex) { + runlockedChan <- true + }) + defer patchRUnlock.Unpatch() + + // Lock obfMutex for writing, so that we can open the file before blockFile() obtains the write mutex + pdb.store.obfMutex.Lock() + + // Launch blockFile in separate goroutine so that we can open file in the interim + go func() { + pdb.store.blockFile(0) + blockFileCompleteChan <- true + }() + + // Read twice from runlockedChan, for both wc and obfMutex unlocks + <-runlockedChan + <-runlockedChan + + // Open file + _, err = pdb.store.openFileFunc(0) + if err != nil { + t.Fatalf("TestBlockFileSingleCPU: Error openning file: %s", err) + } + + // Unlock write mutex to let blockFile() continue exection + pdb.store.obfMutex.Unlock() + + // Wait for blockFile() to complete + <-blockFileCompleteChan +}