2022-07-02 18:38:34 +00:00
/ *
Copyright 2022 Erigon contributors
Licensed under the Apache License , Version 2.0 ( the "License" ) ;
you may not use this file except in compliance with the License .
You may obtain a copy of the License at
http : //www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing , software
distributed under the License is distributed on an "AS IS" BASIS ,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
See the License for the specific language governing permissions and
limitations under the License .
* /
package state
import (
"bytes"
"encoding/binary"
"github.com/ledgerwatch/erigon-lib/compress"
2022-12-10 08:38:02 +00:00
"github.com/ledgerwatch/erigon-lib/recsplit"
2022-07-02 18:38:34 +00:00
"github.com/ledgerwatch/erigon-lib/recsplit/eliasfano32"
)
// Algorithms for reconstituting the state from state history
type ReconItem struct {
2022-10-21 08:31:23 +00:00
g * compress . Getter
2022-07-02 18:38:34 +00:00
key [ ] byte
txNum uint64
startTxNum uint64
endTxNum uint64
startOffset uint64
lastOffset uint64
}
type ReconHeap [ ] * ReconItem
func ( rh ReconHeap ) Len ( ) int {
return len ( rh )
}
// Less (part of heap.Interface) compares two links. For persisted links, those with the lower block heights get evicted first. This means that more recently persisted links are preferred.
// For non-persisted links, those with the highest block heights get evicted first. This is to prevent "holes" in the block heights that may cause inability to
// insert headers in the ascending order of their block heights.
func ( rh ReconHeap ) Less ( i , j int ) bool {
c := bytes . Compare ( rh [ i ] . key , rh [ j ] . key )
if c == 0 {
return rh [ i ] . txNum < rh [ j ] . txNum
}
return c < 0
}
// Swap (part of heap.Interface) moves two links in the queue into each other's places. Note that each link has idx attribute that is getting adjusted during
// the swap. The idx attribute allows the removal of links from the middle of the queue (in case if links are getting invalidated due to
// failed verification of unavailability of parent headers)
func ( rh ReconHeap ) Swap ( i , j int ) {
rh [ i ] , rh [ j ] = rh [ j ] , rh [ i ]
}
// Push (part of heap.Interface) places a new link onto the end of queue. Note that idx attribute is set to the correct position of the new link
func ( rh * ReconHeap ) Push ( x interface { } ) {
// Push and Pop use pointer receivers because they modify the slice's length,
// not just its contents.
l := x . ( * ReconItem )
* rh = append ( * rh , l )
}
// Pop (part of heap.Interface) removes the first link from the queue
func ( rh * ReconHeap ) Pop ( ) interface { } {
old := * rh
n := len ( old )
x := old [ n - 1 ]
2022-12-04 09:19:09 +00:00
old [ n - 1 ] = nil
2022-07-02 18:38:34 +00:00
* rh = old [ 0 : n - 1 ]
return x
}
2023-01-07 05:30:57 +00:00
type ReconHeapOlderFirst struct {
ReconHeap
}
func ( rh ReconHeapOlderFirst ) Less ( i , j int ) bool {
c := bytes . Compare ( rh . ReconHeap [ i ] . key , rh . ReconHeap [ j ] . key )
if c == 0 {
return rh . ReconHeap [ i ] . txNum >= rh . ReconHeap [ j ] . txNum
}
return c < 0
}
2022-12-10 08:38:02 +00:00
type ScanIteratorInc struct {
g * compress . Getter
2022-10-21 08:31:23 +00:00
key [ ] byte
nextTxNum uint64
hasNext bool
2022-07-02 18:38:34 +00:00
}
2022-12-10 08:38:02 +00:00
func ( sii * ScanIteratorInc ) advance ( ) {
if ! sii . hasNext {
return
}
if sii . key == nil {
sii . hasNext = false
return
}
val , _ := sii . g . NextUncompressed ( )
max := eliasfano32 . Max ( val )
sii . nextTxNum = max
if sii . g . HasNext ( ) {
sii . key , _ = sii . g . NextUncompressed ( )
} else {
sii . key = nil
2022-07-02 18:38:34 +00:00
}
}
2022-12-10 08:38:02 +00:00
func ( sii * ScanIteratorInc ) HasNext ( ) bool {
return sii . hasNext
2022-07-02 18:38:34 +00:00
}
2023-01-17 07:16:33 +00:00
func ( sii * ScanIteratorInc ) Next ( ) ( uint64 , error ) {
n := sii . nextTxNum
sii . advance ( )
2022-12-24 06:11:09 +00:00
return n , nil
2022-12-10 08:38:02 +00:00
}
func ( hs * HistoryStep ) iterateTxs ( ) * ScanIteratorInc {
var sii ScanIteratorInc
sii . g = hs . indexFile . getter
sii . g . Reset ( 0 )
if sii . g . HasNext ( ) {
sii . key , _ = sii . g . NextUncompressed ( )
sii . hasNext = true
} else {
sii . hasNext = false
}
sii . advance ( )
return & sii
2022-07-02 18:38:34 +00:00
}
2022-12-10 08:38:02 +00:00
type HistoryIteratorInc struct {
uptoTxNum uint64
indexG * compress . Getter
historyG * compress . Getter
r * recsplit . IndexReader
2022-10-21 08:31:23 +00:00
key [ ] byte
2022-12-10 08:38:02 +00:00
nextKey [ ] byte
nextVal [ ] byte
2022-10-21 08:31:23 +00:00
hasNext bool
compressVals bool
2022-07-02 18:38:34 +00:00
}
2022-12-10 08:38:02 +00:00
func ( hs * HistoryStep ) interateHistoryBeforeTxNum ( txNum uint64 ) * HistoryIteratorInc {
var hii HistoryIteratorInc
hii . indexG = hs . indexFile . getter
hii . historyG = hs . historyFile . getter
hii . r = hs . historyFile . reader
hii . compressVals = hs . compressVals
hii . indexG . Reset ( 0 )
if hii . indexG . HasNext ( ) {
hii . key , _ = hii . indexG . NextUncompressed ( )
hii . uptoTxNum = txNum
hii . hasNext = true
} else {
hii . hasNext = false
}
hii . advance ( )
return & hii
}
func ( hii * HistoryIteratorInc ) advance ( ) {
if ! hii . hasNext {
return
}
if hii . key == nil {
hii . hasNext = false
return
}
hii . nextKey = nil
for hii . nextKey == nil && hii . key != nil {
val , _ := hii . indexG . NextUncompressed ( )
2022-10-15 01:21:15 +00:00
ef , _ := eliasfano32 . ReadEliasFano ( val )
2022-12-10 08:38:02 +00:00
if n , ok := ef . Search ( hii . uptoTxNum ) ; ok {
var txKey [ 8 ] byte
binary . BigEndian . PutUint64 ( txKey [ : ] , n )
offset := hii . r . Lookup2 ( txKey [ : ] , hii . key )
hii . historyG . Reset ( offset )
hii . nextKey = hii . key
if hii . compressVals {
hii . nextVal , _ = hii . historyG . Next ( nil )
} else {
hii . nextVal , _ = hii . historyG . NextUncompressed ( )
}
2022-10-15 01:21:15 +00:00
}
2022-12-10 08:38:02 +00:00
if hii . indexG . HasNext ( ) {
hii . key , _ = hii . indexG . NextUncompressed ( )
2022-10-15 01:21:15 +00:00
} else {
2022-12-10 08:38:02 +00:00
hii . key = nil
2022-07-02 18:38:34 +00:00
}
}
2022-12-10 08:38:02 +00:00
if hii . nextKey == nil {
hii . hasNext = false
}
2022-07-02 18:38:34 +00:00
}
2022-12-10 08:38:02 +00:00
func ( hii * HistoryIteratorInc ) HasNext ( ) bool {
return hii . hasNext
2022-07-02 18:38:34 +00:00
}
2022-12-24 06:11:09 +00:00
func ( hii * HistoryIteratorInc ) Next ( ) ( [ ] byte , [ ] byte , error ) {
2022-12-10 08:38:02 +00:00
k , v := hii . nextKey , hii . nextVal
hii . advance ( )
2022-12-24 06:11:09 +00:00
return k , v , nil
2022-07-02 18:38:34 +00:00
}