96 lines
3.0 KiB
Nim
96 lines
3.0 KiB
Nim
|
# Nimbus
|
||
|
# Copyright (c) 2021-2024 Status Research & Development GmbH
|
||
|
# Licensed under either of
|
||
|
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
|
||
|
# http://www.apache.org/licenses/LICENSE-2.0)
|
||
|
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or
|
||
|
# http://opensource.org/licenses/MIT)
|
||
|
# at your option. This file may not be copied, modified, or distributed except
|
||
|
# according to those terms.
|
||
|
|
||
|
{.push raises: [].}
|
||
|
|
||
|
import
|
||
|
std/[os, tables],
|
||
|
stew/[interval_set, keyed_queue, sorted_set],
|
||
|
results,
|
||
|
../../fluffy/eth_data/era1
|
||
|
|
||
|
const
|
||
|
NumOpenEra1DbBlocks* = 10
|
||
|
|
||
|
type
|
||
|
Era1DbError* = enum
|
||
|
NothingWrong = 0
|
||
|
|
||
|
Era1DbBlocks* = object
|
||
|
## Capability of an `era1` file, to be indexed by starting block num
|
||
|
fileName*: string # File name on disk
|
||
|
nBlocks*: uint # Number of blocks available
|
||
|
|
||
|
Era1DbRef* = ref object
|
||
|
dir*: string # Database folder
|
||
|
blocks*: KeyedQueue[uint64,Era1File] # Era1 block on disk
|
||
|
byBlkNum*: SortedSet[uint64,Era1DbBlocks] # File access info
|
||
|
ranges*: IntervalSetRef[uint64,uint64] # Covered ranges
|
||
|
|
||
|
# ------------------------------------------------------------------------------
|
||
|
# Private helpers
|
||
|
# ------------------------------------------------------------------------------
|
||
|
|
||
|
proc load(db: Era1DbRef, eFile: string) =
|
||
|
let
|
||
|
path = db.dir / eFile
|
||
|
dsc = Era1File.open(path).valueOr:
|
||
|
return
|
||
|
key = dsc.blockIdx.startNumber
|
||
|
|
||
|
if db.blocks.lruFetch(key).isOk or dsc.blockIdx.offsets.len == 0:
|
||
|
dsc.close()
|
||
|
else:
|
||
|
# Add to LRU table
|
||
|
while NumOpenEra1DbBlocks <= db.blocks.len:
|
||
|
db.blocks.shift.value.data.close() # unqueue first/least item
|
||
|
discard db.blocks.lruAppend(key, dsc, NumOpenEra1DbBlocks)
|
||
|
|
||
|
# Add to index list
|
||
|
let w = db.byBlkNum.findOrInsert(key).valueOr:
|
||
|
raiseAssert "Load error, index corrupted: " & $error
|
||
|
if w.data.nBlocks != 0:
|
||
|
discard db.ranges.reduce(key, key+w.data.nBlocks.uint64-1)
|
||
|
w.data.fileName = eFile
|
||
|
w.data.nBlocks = dsc.blockIdx.offsets.len.uint
|
||
|
discard db.ranges.merge(key, key+dsc.blockIdx.offsets.len.uint64-1)
|
||
|
|
||
|
# ------------------------------------------------------------------------------
|
||
|
# Public constructor
|
||
|
# ------------------------------------------------------------------------------
|
||
|
|
||
|
proc init*(
|
||
|
T: type Era1DbRef;
|
||
|
dir: string;
|
||
|
): T =
|
||
|
## Load `era1` index
|
||
|
result = T(
|
||
|
dir: dir,
|
||
|
byBlkNum: SortedSet[uint64,Era1DbBlocks].init(),
|
||
|
ranges: IntervalSetRef[uint64,uint64].init())
|
||
|
|
||
|
try:
|
||
|
for w in dir.walkDir(relative=true):
|
||
|
if w.kind in {pcFile, pcLinkToFile}:
|
||
|
result.load w.path
|
||
|
except CatchableError:
|
||
|
discard
|
||
|
|
||
|
proc dispose*(db: Era1DbRef) =
|
||
|
for w in db.blocks.nextValues:
|
||
|
w.close()
|
||
|
db.blocks.clear()
|
||
|
db.ranges.clear()
|
||
|
db.byBlkNum.clear()
|
||
|
|
||
|
# ------------------------------------------------------------------------------
|
||
|
# End
|
||
|
# ------------------------------------------------------------------------------
|