// cacheBlockIfNotYetDirtyLocked puts a block into the cache, but only
// does so if the block isn't already marked as dirty in the cache.
// This is useful when operating on a dirty copy of a block that may
// already be in the cache.
345206
func (fbo *folderBlockOps) cacheBlockIfNotYetDirtyLocked(
	ctx context.Context, lState *kbfssync.LockState, ptr data.BlockPointer,
	file data.Path, block data.Block) error {
	fbo.blockLock.AssertLocked(lState)
	df := fbo.getOrCreateDirtyFileLocked(lState, file)
	needsCaching, isSyncing := df.SetBlockDirty(ptr)

	if needsCaching {
		err := fbo.config.DirtyBlockCache().Put(
			ctx, fbo.id(), ptr, file.Branch, block)
		if err != nil {
			return err
		}
	}

	if isSyncing {
		fbo.doDeferWrite = true
	}
	return nil
}
871385
func (c *ConfigLocal) MakeDiskBlockCacheIfNotExists() error {
	c.lock.Lock()
	defer c.lock.Unlock()
	if c.diskBlockCache != nil {
		return nil
	}
	switch c.diskCacheMode {
	case DiskCacheModeOff:
		return nil
	case DiskCacheModeLocal:
		return c.resetDiskBlockCacheLocked()
	case DiskCacheModeRemote:
		dbc, err := NewDiskBlockCacheRemote(c.kbCtx, c)
		if err != nil {
			return err
		}
		c.diskBlockCache = dbc
		return nil
	}
	return nil
}
74364
func (b *blockManager) BlockHeadersSynced() bool {
	b.syncPeerMutex.RLock()
	defer b.syncPeerMutex.RUnlock()

	// Figure out the latest block we know.
	header, height, err := b.server.BlockHeaders.ChainTip()
	if err != nil {
		return false
	}

	// There is no last checkpoint if checkpoints are disabled or there are
	// none for this current network.
	checkpoints := b.server.chainParams.Checkpoints
	if len(checkpoints) != 0 {
		// We aren't current if the newest block we know of isn't ahead
		// of all checkpoints.
		if checkpoints[len(checkpoints)-1].Height >= int32(height) {
			return false
		}
	}

	// If we have a syncPeer and are below the block we are syncing to, we
	// are not current.
	if b.syncPeer != nil && int32(height) < b.syncPeer.LastBlock() {
		return false
	}

	// If our time source (median times of all the connected peers) is at
	// least 24 hours ahead of our best known block, we aren't current.
	minus24Hours := b.server.timeSource.AdjustedTime().Add(-24 * time.Hour)
	if header.Timestamp.Before(minus24Hours) {
		return false
	}

	// If we have no sync peer, we can assume we're current for now.
	if b.syncPeer == nil {
		return true
	}

	// If we have a syncPeer and the peer reported a higher known block
	// height on connect than we know the peer already has, we're probably
	// not current. If the peer is lying to us, other code will disconnect
	// it and then we'll re-check and notice that we're actually current.
	return b.syncPeer.LastBlock() >= b.syncPeer.StartingHeight()
}
1085196
func (fbo *folderBlockOps) getDirtyDirUnrefsLocked(
	lState *kbfssync.LockState, ptr data.BlockPointer) []data.BlockInfo {
	fbo.blockLock.AssertRLocked(lState)
	return fbo.dirtyDirs[ptr]
}
566995
func (c *baseFlowController) IsNewlyBlocked() (bool, protocol.ByteCount) {
	if c.sendWindowSize() != 0 || c.sendWindow == c.lastBlockedAt {
		return false, 0
	}
	c.lastBlockedAt = c.sendWindow
	return true, c.sendWindow
}
341877
func (fbo *folderBlockOps) notifyErrListenersLocked(
	lState *kbfssync.LockState, ptr data.BlockPointer, err error) {
	fbo.blockLock.AssertLocked(lState)
	if isRecoverableBlockError(err) {
		// Don't bother any listeners with this error, since the sync
		// will be retried.  Unless the sync has reached its retry
		// limit, but in that case the listeners will just proceed as
		// normal once the dirty block cache bytes are freed, and
		// that's ok since this error isn't fatal.
		return
	}
	df := fbo.dirtyFiles[ptr]
	if df != nil {
		df.NotifyErrListeners(err)
	}
}
147227
func (fbo *folderBlockOps) GetDirtyFileBlockRefs(
	lState *kbfssync.LockState) []data.BlockRef {
	fbo.blockLock.RLock(lState)
	defer fbo.blockLock.RUnlock(lState)
	var dirtyRefs []data.BlockRef
	for ref := range fbo.unrefCache {
		dirtyRefs = append(dirtyRefs, ref)
	}
	return dirtyRefs
}
131647
func (c *ConfigLocal) SetDiskBlockCacheFraction(fraction float64) {
	c.lock.Lock()
	defer c.lock.Unlock()
	c.diskBlockCacheFraction = fraction
}
1321345
func (bg *Reader) cacheHasBlockFor(base int64) (exists bool, next int64) {
	bg.mu.RLock()
	defer bg.mu.RUnlock()
	if bg.cache == nil {
		return false, -1
	}
	return bg.cache.Peek(base)
}
447456
func (b *BitcoindFilteredChainView) onFilteredBlockDisconnected(height int32,
	hash chainhash.Hash) {

	log.Debugf("got disconnected block at height %d: %v", height,
		hash)

	filteredBlock := &FilteredBlock{
		Hash:   hash,
		Height: uint32(height),
	}

	b.blockQueue.Add(&blockEvent{
		eventType: disconnected,
		block:     filteredBlock,
	})
}
589182
func newDiskBlockCacheLocal(config diskBlockCacheConfig,
	cacheType diskLimitTrackerType, dirPath string) (
	cache *DiskBlockCacheLocal, err error) {
	log := config.MakeLogger("DBC")
	defer func() {
		if err != nil {
			log.Error("Error initializing disk cache: %+v", err)
		}
	}()
	versionPath, err := getVersionedPathForDiskCache(
		log, dirPath, "block", currentDiskBlockCacheVersion)
	if err != nil {
		return nil, err
	}
	blockDbPath := filepath.Join(versionPath, blockDbFilename)
	blockStorage, err := storage.OpenFile(blockDbPath, false)
	if err != nil {
		return nil, err
	}
	defer func() {
		if err != nil {
			blockStorage.Close()
		}
	}()
	metaDbPath := filepath.Join(versionPath, metaDbFilename)
	metadataStorage, err := storage.OpenFile(metaDbPath, false)
	if err != nil {
		return nil, err
	}
	defer func() {
		if err != nil {
			metadataStorage.Close()
		}
	}()
	tlfDbPath := filepath.Join(versionPath, tlfDbFilename)
	tlfStorage, err := storage.OpenFile(tlfDbPath, false)
	if err != nil {
		return nil, err
	}
	defer func() {
		if err != nil {
			tlfStorage.Close()
		}
	}()
	lastUnrefDbPath := filepath.Join(versionPath, lastUnrefDbFilename)
	lastUnrefStorage, err := storage.OpenFile(lastUnrefDbPath, false)
	if err != nil {
		return nil, err
	}
	defer func() {
		if err != nil {
			lastUnrefStorage.Close()
		}
	}()
	cache, err = newDiskBlockCacheLocalFromStorage(config, cacheType,
		blockStorage, metadataStorage, tlfStorage, lastUnrefStorage)
	if err != nil {
		return nil, err
	}
	cache.dirPath = dirPath
	return cache, nil
}
569663
func (apic *APICache) removeCachedBlock(cachedBlock *CachedBlock) {
	if cachedBlock == nil {
		return
	}
	// remove the block from the expiration queue
	apic.expireQueue.RemoveBlock(cachedBlock)
	// remove from block cache
	if hash, err := chainhash.NewHashFromStr(cachedBlock.hash); err != nil {
		delete(apic.blockCache, *hash)
	}
	delete(apic.MainchainBlocks, int64(cachedBlock.height))
}
290654
func (c DiskBlockCacheClient) PutBlock(ctx context.Context, __arg PutBlockArg) (err error) {
	err = c.Cli.Call(ctx, "kbgitkbfs.1.DiskBlockCache.PutBlock", []interface{}{__arg}, nil)
	return
}
52947
func (cache *DiskBlockCacheLocal) encodeBlockCacheEntry(buf []byte,
	serverHalf kbfscrypto.BlockCryptKeyServerHalf) ([]byte, error) {
	entry := diskBlockCacheEntry{
		Buf:        buf,
		ServerHalf: serverHalf,
	}
	return cache.config.Codec().Encode(&entry)
}
498731
func (bt *blockTree) getNextDirtyBlockAtOffsetAtLevel(ctx context.Context,
	pblock BlockWithPtrs, off Offset, rtype BlockReqType,
	dirtyBcache IsDirtyProvider, parentBlocks []ParentBlockAndChildIndex) (
	ptr BlockPointer, newParentBlocks []ParentBlockAndChildIndex,
	block BlockWithPtrs, nextBlockStartOff, startOff Offset, err error) {
	// Search along paths of dirty blocks until we find a dirty leaf
	// block with an offset equal or greater than `off`.
	checkedPrevBlock := false
	for i := 0; i < pblock.NumIndirectPtrs(); i++ {
		info, iptrOff := pblock.IndirectPtr(i)
		iptrLess := iptrOff.Less(off)
		if iptrLess && i != pblock.NumIndirectPtrs()-1 {
			continue
		}

		// No need to check the previous block if we align exactly
		// with `off`, or this is the right-most leaf block.
		if iptrLess || iptrOff.Equals(off) {
			checkedPrevBlock = true
		}

		// If we haven't checked the previous block yet, do so now
		// since it contains `off`.
		index := -1
		nextBlockStartOff = nil
		startOff = pblock.FirstOffset()
		var prevPtr BlockPointer
		if !checkedPrevBlock && i > 0 {
			prevInfo, _ := pblock.IndirectPtr(i - 1)
			prevPtr = prevInfo.BlockPointer
		}
		if prevPtr.IsValid() && dirtyBcache.IsDirty(
			bt.file.Tlf, prevPtr, bt.file.Branch) {
			// Since we checked the previous block, stay on this
			// index for the next iteration.
			i--
			index = i
		} else if dirtyBcache.IsDirty(
			bt.file.Tlf, info.BlockPointer, bt.file.Branch) {
			// Now check the current block.
			index = i
		}
		checkedPrevBlock = true

		// Try the next child.
		if index == -1 {
			continue
		}

		indexInfo, indexOff := pblock.IndirectPtr(index)
		ptr = indexInfo.BlockPointer
		block, _, err = bt.getter(ctx, bt.kmd, ptr, bt.file, rtype)
		if err != nil {
			return ZeroPtr, nil, nil, nil, nil, err
		}

		newParentBlocks = append(parentBlocks,
			ParentBlockAndChildIndex{pblock, index})
		// If this is a leaf block, we're done.
		if !block.IsIndirect() {
			// There is more to read if we ever took a path through a
			// ptr that wasn't the final ptr in its respective list.
			if index != pblock.NumIndirectPtrs()-1 {
				_, nextBlockStartOff = pblock.IndirectPtr(index + 1)
			}
			return ptr, newParentBlocks, block, nextBlockStartOff, indexOff, nil
		}

		// Recurse to the next lower level.
		ptr, newParentBlocks, block, nextBlockStartOff, startOff, err =
			bt.getNextDirtyBlockAtOffsetAtLevel(
				ctx, block, off, rtype, dirtyBcache, newParentBlocks)
		if err != nil {
			return ZeroPtr, nil, nil, nil, nil, err
		}
		// If we found a block, we're done.
		if block != nil {
			// If the block didn't have an immediate sibling to the
			// right, set the next offset to the parent block's
			// sibling's offset.
			if nextBlockStartOff == nil && index != pblock.NumIndirectPtrs()-1 {
				_, nextBlockStartOff = pblock.IndirectPtr(index + 1)
			}
			return ptr, newParentBlocks, block, nextBlockStartOff, startOff, nil
		}
	}

	// There's no dirty block at or after `off`.
	return ZeroPtr, nil, nil, pblock.FirstOffset(), pblock.FirstOffset(), nil
}
139703
func (cache *DiskBlockCacheLocal) checkCacheLocked(method string) error {
	select {
	case <-cache.startedCh:
	case <-cache.startErrCh:
		// The cache will never be started. No need for a stack here since this
		// could happen anywhere.
		return DiskCacheStartingError{method}
	default:
		// If the cache hasn't started yet, return an error.  No need for a
		// stack here since this could happen anywhere.
		return DiskCacheStartingError{method}
	}
	// shutdownCh has to be checked under lock, otherwise we can race.
	select {
	case <-cache.shutdownCh:
		return errors.WithStack(DiskCacheClosedError{method})
	default:
	}
	if cache.blockDb == nil {
		return errors.WithStack(DiskCacheClosedError{method})
	}
	return nil
}
1352810
func (df *DirtyFile) ResetSyncingBlocksToDirty() {
	df.lock.Lock()
	defer df.lock.Unlock()
	// Reset all syncing blocks to just be dirty again
	syncFinishedNeeded := false
	for ptr, state := range df.fileBlockStates {
		if state.orphaned {
			// This block will never be sync'd again, so clear any
			// bytes from the buffer.
			if state.sync == blockSyncing {
				df.dirtyBcache.UpdateUnsyncedBytes(df.Path.Tlf,
					-state.syncSize, true)
			} else if state.sync == blockSynced {
				// Some blocks did finish, so we might be able to
				// increase our buffer size.
				syncFinishedNeeded = true
			}
			state.syncSize = 0
			delete(df.fileBlockStates, ptr)
			continue
		}
		if state.sync == blockSynced {
			// Re-dirty the unsynced bytes (but don't touch the total
			// bytes).
			df.dirtyBcache.BlockSyncFinished(df.Path.Tlf, -state.syncSize)
		} else if state.sync == blockSyncing {
			df.dirtyBcache.UpdateSyncingBytes(df.Path.Tlf, -state.syncSize)
		}
		if state.sync != blockNotSyncing {
			state.copy = blockAlreadyCopied
			state.sync = blockNotSyncing
			state.syncSize = 0
			df.fileBlockStates[ptr] = state
		}
	}
	if syncFinishedNeeded {
		df.dirtyBcache.SyncFinished(df.Path.Tlf, df.totalSyncBytes)
	}
	df.totalSyncBytes = 0 // all the blocks need to be re-synced.
}