rework indexing strategy to use an enum (#694)

This commit is contained in:
Dmitriy Ryajov 2024-02-07 13:13:27 -06:00 committed by GitHub
parent 2cf892c467
commit 2fc538337b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 71 additions and 67 deletions

View File

@ -130,10 +130,10 @@ proc prepareEncodingData(
## ##
let let
strategy = SteppedIndexingStrategy.new( strategy = SteppedStrategy.init(
firstIndex = 0, firstIndex = 0,
lastIndex = params.rounded - 1, lastIndex = params.rounded - 1,
numberOfIterations = params.steps iterations = params.steps
) )
indicies = toSeq(strategy.getIndicies(step)) indicies = toSeq(strategy.getIndicies(step))
pendingBlocksIter = self.getPendingBlocks(manifest, indicies.filterIt(it < manifest.blocksCount)) pendingBlocksIter = self.getPendingBlocks(manifest, indicies.filterIt(it < manifest.blocksCount))
@ -179,10 +179,10 @@ proc prepareDecodingData(
## ##
let let
strategy = SteppedIndexingStrategy.new( strategy = SteppedStrategy.init(
firstIndex = 0, firstIndex = 0,
lastIndex = encoded.blocksCount - 1, lastIndex = encoded.blocksCount - 1,
numberOfIterations = encoded.steps iterations = encoded.steps
) )
indicies = toSeq(strategy.getIndicies(step)) indicies = toSeq(strategy.getIndicies(step))
pendingBlocksIter = self.getPendingBlocks(encoded, indicies) pendingBlocksIter = self.getPendingBlocks(encoded, indicies)

View File

@ -1,5 +1,3 @@
import std/sequtils
import ./errors import ./errors
import ./utils import ./utils
import ./utils/asynciter import ./utils/asynciter
@ -7,6 +5,19 @@ import ./utils/asynciter
{.push raises: [].} {.push raises: [].}
type type
StrategyType* = enum
# Simplest approach:
# 0 => 0, 1, 2
# 1 => 3, 4, 5
# 2 => 6, 7, 8
LinearStrategy,
# Stepped indexing:
# 0 => 0, 3, 6
# 1 => 1, 4, 7
# 2 => 2, 5, 8
SteppedStrategy
# Representing a strategy for grouping indices (of blocks usually) # Representing a strategy for grouping indices (of blocks usually)
# Given an interation-count as input, will produce a seq of # Given an interation-count as input, will produce a seq of
# selected indices. # selected indices.
@ -15,57 +26,39 @@ type
IndexingWrongIndexError* = object of IndexingError IndexingWrongIndexError* = object of IndexingError
IndexingWrongIterationsError* = object of IndexingError IndexingWrongIterationsError* = object of IndexingError
IndexingStrategy* = ref object of RootObj IndexingStrategy* = object
strategyType*: StrategyType
firstIndex*: int # Lowest index that can be returned firstIndex*: int # Lowest index that can be returned
lastIndex*: int # Highest index that can be returned lastIndex*: int # Highest index that can be returned
numberOfIterations*: int # getIndices(iteration) will run from 0 ..< numberOfIterations iterations*: int # getIndices(iteration) will run from 0 ..< iterations
step*: int step*: int
# Simplest approach: func checkIteration(self: IndexingStrategy, iteration: int): void {.raises: [IndexingError].} =
# 0 => 0, 1, 2 if iteration >= self.iterations:
# 1 => 3, 4, 5
# 2 => 6, 7, 8
LinearIndexingStrategy* = ref object of IndexingStrategy
# Stepped indexing:
# 0 => 0, 3, 6
# 1 => 1, 4, 7
# 2 => 2, 5, 8
SteppedIndexingStrategy* = ref object of IndexingStrategy
proc checkIteration(
self: IndexingStrategy,
iteration: int): void {.raises: [IndexingError].} =
if iteration >= self.numberOfIterations:
raise newException( raise newException(
IndexingError, IndexingError,
"Indexing iteration can't be greater than or equal to numberOfIterations.") "Indexing iteration can't be greater than or equal to iterations.")
method getIndicies*(
self: IndexingStrategy,
iteration: int): Iter[int] {.base, raises: [IndexingError].} =
raiseAssert("Not implemented")
proc getIter(first, last, step: int): Iter[int] = proc getIter(first, last, step: int): Iter[int] =
var var
finish = false finish = false
cur = first cur = first
proc get(): int =
func get(): int =
result = cur result = cur
cur += step cur += step
if cur > last: if cur > last:
finish = true finish = true
proc isFinished(): bool = func isFinished(): bool =
finish finish
Iter.new(get, isFinished) Iter.new(get, isFinished)
method getIndicies*( func getLinearIndicies(
self: LinearIndexingStrategy, self: IndexingStrategy,
iteration: int): Iter[int] {.raises: [IndexingError].} = iteration: int): Iter[int] {.raises: [IndexingError].} =
self.checkIteration(iteration) self.checkIteration(iteration)
let let
@ -74,33 +67,44 @@ method getIndicies*(
getIter(first, last, 1) getIter(first, last, 1)
method getIndicies*( func getSteppedIndicies(
self: SteppedIndexingStrategy, self: IndexingStrategy,
iteration: int): Iter[int] {.raises: [IndexingError].} = iteration: int): Iter[int] {.raises: [IndexingError].} =
self.checkIteration(iteration) self.checkIteration(iteration)
let let
first = self.firstIndex + iteration first = self.firstIndex + iteration
last = self.lastIndex last = self.lastIndex
getIter(first, last, self.numberOfIterations) getIter(first, last, self.iterations)
func getIndicies*(
self: IndexingStrategy,
iteration: int): Iter[int] {.raises: [IndexingError].} =
case self.strategyType
of StrategyType.LinearStrategy:
self.getLinearIndicies(iteration)
of StrategyType.SteppedStrategy:
self.getSteppedIndicies(iteration)
func init*(
strategy: StrategyType,
firstIndex, lastIndex, iterations: int): IndexingStrategy {.raises: [IndexingError].} =
proc new*(
T: type IndexingStrategy,
firstIndex, lastIndex, numberOfIterations: int): T {.raises: [IndexingError].} =
if firstIndex > lastIndex: if firstIndex > lastIndex:
raise newException( raise newException(
IndexingWrongIndexError, IndexingWrongIndexError,
"firstIndex (" & $firstIndex & ") can't be greater than lastIndex (" & $lastIndex & ")") "firstIndex (" & $firstIndex & ") can't be greater than lastIndex (" & $lastIndex & ")")
if numberOfIterations <= 0: if iterations <= 0:
raise newException( raise newException(
IndexingWrongIterationsError, IndexingWrongIterationsError,
"numberOfIteration (" & $numberOfIterations & ") must be greater than zero.") "iterations (" & $iterations & ") must be greater than zero.")
T( IndexingStrategy(
strategyType: strategy,
firstIndex: firstIndex, firstIndex: firstIndex,
lastIndex: lastIndex, lastIndex: lastIndex,
numberOfIterations: numberOfIterations, iterations: iterations,
step: divUp((lastIndex - firstIndex), numberOfIterations)) step: divUp((lastIndex - firstIndex), iterations))

View File

@ -341,7 +341,7 @@ proc new*(
let let
strategy = if strategy.isNone: strategy = if strategy.isNone:
? SteppedIndexingStrategy.new( ? SteppedStrategy.init(
0, manifest.blocksCount - 1, manifest.numSlots).catch 0, manifest.blocksCount - 1, manifest.numSlots).catch
else: else:
strategy.get strategy.get

View File

@ -4,9 +4,9 @@ import pkg/questionable
import pkg/chronos import pkg/chronos
type type
Function*[T, U] = proc(fut: T): U {.raises: [CatchableError], gcsafe, closure.} Function*[T, U] = proc(fut: T): U {.raises: [CatchableError], gcsafe, noSideEffect.}
IsFinished* = proc(): bool {.raises: [], gcsafe, closure.} IsFinished* = proc(): bool {.raises: [], gcsafe, noSideEffect.}
GenNext*[T] = proc(): T {.raises: [CatchableError], gcsafe, closure.} GenNext*[T] = proc(): T {.raises: [CatchableError], gcsafe.}
Iter*[T] = ref object Iter*[T] = ref object
finished: bool finished: bool
next*: GenNext[T] next*: GenNext[T]

View File

@ -83,7 +83,7 @@ proc createSlotTree(self: ProvingTestEnvironment, dSlotIndex: uint64): Future[Po
let let
slotSize = (bytesPerBlock * numberOfSlotBlocks).uint64 slotSize = (bytesPerBlock * numberOfSlotBlocks).uint64
blocksInSlot = slotSize div bytesPerBlock.uint64 blocksInSlot = slotSize div bytesPerBlock.uint64
datasetBlockIndexingStrategy = SteppedIndexingStrategy.new(0, self.datasetBlocks.len - 1, totalNumberOfSlots) datasetBlockIndexingStrategy = SteppedStrategy.init(0, self.datasetBlocks.len - 1, totalNumberOfSlots)
datasetBlockIndices = toSeq(datasetBlockIndexingStrategy.getIndicies(dSlotIndex.int)) datasetBlockIndices = toSeq(datasetBlockIndexingStrategy.getIndicies(dSlotIndex.int))
let let

View File

@ -201,7 +201,7 @@ suite "Slot builder":
test "Should build slot hashes for all slots": test "Should build slot hashes for all slots":
let let
steppedStrategy = SteppedIndexingStrategy.new(0, numTotalBlocks - 1, numSlots) steppedStrategy = SteppedStrategy.init(0, numTotalBlocks - 1, numSlots)
slotBuilder = SlotsBuilder.new( slotBuilder = SlotsBuilder.new(
localStore, localStore,
protectedManifest, protectedManifest,
@ -224,7 +224,7 @@ suite "Slot builder":
test "Should build slot trees for all slots": test "Should build slot trees for all slots":
let let
steppedStrategy = SteppedIndexingStrategy.new(0, numTotalBlocks - 1, numSlots) steppedStrategy = SteppedStrategy.init(0, numTotalBlocks - 1, numSlots)
slotBuilder = SlotsBuilder.new( slotBuilder = SlotsBuilder.new(
localStore, localStore,
protectedManifest, protectedManifest,
@ -272,7 +272,7 @@ suite "Slot builder":
test "Should build correct verification root": test "Should build correct verification root":
let let
steppedStrategy = SteppedIndexingStrategy.new(0, numTotalBlocks - 1, numSlots) steppedStrategy = SteppedStrategy.init(0, numTotalBlocks - 1, numSlots)
slotBuilder = SlotsBuilder.new( slotBuilder = SlotsBuilder.new(
localStore, localStore,
protectedManifest, protectedManifest,
@ -301,7 +301,7 @@ suite "Slot builder":
test "Should build correct verification root manifest": test "Should build correct verification root manifest":
let let
steppedStrategy = SteppedIndexingStrategy.new(0, numTotalBlocks - 1, numSlots) steppedStrategy = SteppedStrategy.init(0, numTotalBlocks - 1, numSlots)
slotBuilder = SlotsBuilder.new( slotBuilder = SlotsBuilder.new(
localStore, localStore,
protectedManifest, protectedManifest,

View File

@ -14,8 +14,8 @@ for offset in @[0, 1, 2, 100]:
firstIndex = 0 + offset firstIndex = 0 + offset
lastIndex = 12 + offset lastIndex = 12 + offset
nIters = 3 nIters = 3
linear = LinearIndexingStrategy.new(firstIndex, lastIndex, nIters) linear = LinearStrategy.init(firstIndex, lastIndex, nIters)
stepped = SteppedIndexingStrategy.new(firstIndex, lastIndex, nIters) stepped = SteppedStrategy.init(firstIndex, lastIndex, nIters)
test "linear": test "linear":
check: check:
@ -31,32 +31,32 @@ for offset in @[0, 1, 2, 100]:
suite "Indexing strategies": suite "Indexing strategies":
let let
linear = LinearIndexingStrategy.new(0, 10, 3) linear = LinearStrategy.init(0, 10, 3)
stepped = SteppedIndexingStrategy.new(0, 10, 3) stepped = SteppedStrategy.init(0, 10, 3)
test "smallest range 0": test "smallest range 0":
let let
l = LinearIndexingStrategy.new(0, 0, 1) l = LinearStrategy.init(0, 0, 1)
s = SteppedIndexingStrategy.new(0, 0, 1) s = SteppedStrategy.init(0, 0, 1)
check: check:
toSeq(l.getIndicies(0)) == @[0] toSeq(l.getIndicies(0)) == @[0]
toSeq(s.getIndicies(0)) == @[0] toSeq(s.getIndicies(0)) == @[0]
test "smallest range 1": test "smallest range 1":
let let
l = LinearIndexingStrategy.new(0, 1, 1) l = LinearStrategy.init(0, 1, 1)
s = SteppedIndexingStrategy.new(0, 1, 1) s = SteppedStrategy.init(0, 1, 1)
check: check:
toSeq(l.getIndicies(0)) == @[0, 1] toSeq(l.getIndicies(0)) == @[0, 1]
toSeq(s.getIndicies(0)) == @[0, 1] toSeq(s.getIndicies(0)) == @[0, 1]
test "first index must be smaller than last index": test "first index must be smaller than last index":
expect IndexingWrongIndexError: expect IndexingWrongIndexError:
discard LinearIndexingStrategy.new(10, 0, 1) discard LinearStrategy.init(10, 0, 1)
test "numberOfIterations must be greater than zero": test "iterations must be greater than zero":
expect IndexingWrongIterationsError: expect IndexingWrongIterationsError:
discard LinearIndexingStrategy.new(0, 10, 0) discard LinearStrategy.init(0, 10, 0)
test "linear - oob": test "linear - oob":
expect IndexingError: expect IndexingError: