mutex.Lock during c.recoverFromCorruption()

This commit is contained in:
Larry Ruane 2020-04-23 00:17:42 -06:00 committed by Larry Ruane
parent 1d11751e4e
commit 3873a4d895
1 changed files with 26 additions and 11 deletions

View File

@ -51,20 +51,27 @@ func (c *BlockCache) HashMismatch(prevhash []byte) bool {
return c.latestHash != nil && !bytes.Equal(c.latestHash, prevhash)
}
// Make the block at the given height the lowest height that we don't have.
// In other words, wipe out this height and beyond.
// This should never increase the size of the cache, only decrease.
// Caller should hold c.mutex.Lock().
func (c *BlockCache) setDbFiles(height int) {
index := height - c.firstBlock
if err := c.lengthsFile.Truncate(int64(index * 4)); err != nil {
Log.Fatal("truncate lengths file failed: ", err)
if height < c.nextBlock {
index := height - c.firstBlock
if err := c.lengthsFile.Truncate(int64(index * 4)); err != nil {
Log.Fatal("truncate lengths file failed: ", err)
}
if err := c.blocksFile.Truncate(c.starts[index]); err != nil {
Log.Fatal("truncate blocks file failed: ", err)
}
c.Sync()
c.starts = c.starts[:index+1]
c.nextBlock = height
c.setLatestHash()
}
if err := c.blocksFile.Truncate(c.starts[index]); err != nil {
Log.Fatal("truncate blocks file failed: ", err)
}
c.Sync()
c.starts = c.starts[:index+1]
c.nextBlock = height
c.setLatestHash()
}
// Caller should hold c.mutex.Lock().
func (c *BlockCache) recoverFromCorruption(height int) {
Log.Warning("CORRUPTION detected in db blocks-cache files, height ", height, " redownloading")
c.setDbFiles(height)
@ -86,6 +93,7 @@ func checksum(height int, b []byte) []byte {
return cs.Sum(nil)
}
// Caller should hold (at least) c.mutex.RLock().
func (c *BlockCache) readBlock(height int) *walletrpc.CompactBlock {
blockLen := c.blockLength(height)
b := make([]byte, blockLen+8)
@ -116,6 +124,7 @@ func (c *BlockCache) readBlock(height int) *walletrpc.CompactBlock {
return block
}
// Caller should hold c.mutex.Lock().
func (c *BlockCache) setLatestHash() {
c.latestHash = nil
// There is at least one block; get the last block's hash
@ -132,6 +141,7 @@ func (c *BlockCache) setLatestHash() {
}
// NewBlockCache returns an instance of a block cache object.
// (No locking here, we assume this is single-threaded.)
func NewBlockCache(dbPath string, chainName string, startHeight int, redownload bool) *BlockCache {
c := &BlockCache{}
c.firstBlock = startHeight
@ -298,7 +308,12 @@ func (c *BlockCache) Get(height int) *walletrpc.CompactBlock {
}
block := c.readBlock(height)
if block == nil {
c.recoverFromCorruption(height)
go func() {
// We hold only the read lock, need the exclusive lock.
c.mutex.Lock()
c.recoverFromCorruption(height)
c.mutex.Unlock()
}()
return nil
}
return block