github.com/ledgerwatch/erigon-lib@v1.0.0/kv/kv_interface.go (about) 1 /* 2 Copyright 2022 Erigon contributors 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package kv 18 19 import ( 20 "context" 21 "errors" 22 "fmt" 23 24 "github.com/VictoriaMetrics/metrics" 25 "github.com/ledgerwatch/erigon-lib/kv/iter" 26 "github.com/ledgerwatch/erigon-lib/kv/order" 27 ) 28 29 //Variables Naming: 30 // tx - Database Transaction 31 // txn - Ethereum Transaction (and TxNum - is also number of Etherum Transaction) 32 // blockNum - Ethereum block number - same across all nodes. blockID - auto-increment ID - which can be differrent across all nodes 33 // txNum/txID - same 34 // RoTx - Read-Only Database Transaction. RwTx - read-write 35 // k, v - key, value 36 // ts - TimeStamp. Usually it's Etherum's TransactionNumber (auto-increment ID). Or BlockNumber. 37 // Cursor - low-level mdbx-tide api to navigate over Table 38 // Iter - high-level iterator-like api over Table/InvertedIndex/History/Domain. Has less features than Cursor. See package `iter`. 39 40 //Methods Naming: 41 // Prune: delete old data 42 // Unwind: delete recent data 43 // Get: exact match of criterias 44 // Range: [from, to). from=nil means StartOfTable, to=nil means EndOfTable, rangeLimit=-1 means Unlimited 45 // Range is analog of SQL's: SELECT * FROM Table WHERE k>=from AND k<to ORDER BY k ASC/DESC LIMIT n 46 // Prefix: `Range(Table, prefix, kv.NextSubtree(prefix))` 47 48 //Abstraction Layers: 49 // LowLevel: 50 // 1. DB/Tx - low-level key-value database 51 // 2. Snapshots/FrozenData - immutable files with historical data. May be downloaded at first App 52 // start or auto-generate by moving old data from DB to Snapshots. 53 // Most important difference between DB and Snapshots: creation of 54 // snapshot files (build/merge) doesn't mutate any existing files - only producing new one! 55 // It means we don't need concept of "RwTx" for Snapshots. 56 // Files can become useless/garbage (merged to bigger file) - last reader of this file will 57 // remove it from FileSystem on tx.Rollback(). 58 // Invariant: existing readers can't see new files, new readers can't see garbage files 59 // 60 // MediumLevel: 61 // 1. TemporalDB - abstracting DB+Snapshots. Target is: 62 // - provide 'time-travel' API for data: consistan snapshot of data as of given Timestamp. 63 // - auto-close iterators on Commit/Rollback 64 // - auto-open/close agg.MakeContext() on Begin/Commit/Rollback 65 // - to keep DB small - only for Hot/Recent data (can be update/delete by re-org). 66 // - And TemporalRoTx/TemporalRwTx actaully open Read-Only files view (MakeContext) - no concept of "Read-Write view of snapshot files". 67 // - using next entities: 68 // - InvertedIndex: supports range-scans 69 // - History: can return value of key K as of given TimeStamp. Doesn't know about latest/current 70 // value of key K. Returns NIL if K not changed after TimeStamp. 71 // - Domain: as History but also aware about latest/current value of key K. Can move 72 // cold (updated long time ago) parts of state from db to snapshots. 73 74 // HighLevel: 75 // 1. Application - rely on TemporalDB (Ex: ExecutionLayer) or just DB (Ex: TxPool, Sentry, Downloader). 76 77 const ReadersLimit = 32000 // MDBX_READERS_LIMIT=32767 78 79 // const Unbounded []byte = nil 80 const Unlim int = -1 81 82 var ( 83 ErrAttemptToDeleteNonDeprecatedBucket = errors.New("only buckets from dbutils.ChaindataDeprecatedTables can be deleted") 84 85 DbSize = metrics.GetOrCreateCounter(`db_size`) //nolint 86 TxLimit = metrics.GetOrCreateCounter(`tx_limit`) //nolint 87 TxSpill = metrics.GetOrCreateCounter(`tx_spill`) //nolint 88 TxUnspill = metrics.GetOrCreateCounter(`tx_unspill`) //nolint 89 TxDirty = metrics.GetOrCreateCounter(`tx_dirty`) //nolint 90 91 DbCommitPreparation = metrics.GetOrCreateSummary(`db_commit_seconds{phase="preparation"}`) //nolint 92 //DbGCWallClock = metrics.GetOrCreateSummary(`db_commit_seconds{phase="gc_wall_clock"}`) //nolint 93 //DbGCCpuTime = metrics.GetOrCreateSummary(`db_commit_seconds{phase="gc_cpu_time"}`) //nolint 94 //DbCommitAudit = metrics.GetOrCreateSummary(`db_commit_seconds{phase="audit"}`) //nolint 95 DbCommitWrite = metrics.GetOrCreateSummary(`db_commit_seconds{phase="write"}`) //nolint 96 DbCommitSync = metrics.GetOrCreateSummary(`db_commit_seconds{phase="sync"}`) //nolint 97 DbCommitEnding = metrics.GetOrCreateSummary(`db_commit_seconds{phase="ending"}`) //nolint 98 DbCommitTotal = metrics.GetOrCreateSummary(`db_commit_seconds{phase="total"}`) //nolint 99 100 DbPgopsNewly = metrics.GetOrCreateCounter(`db_pgops{phase="newly"}`) //nolint 101 DbPgopsCow = metrics.GetOrCreateCounter(`db_pgops{phase="cow"}`) //nolint 102 DbPgopsClone = metrics.GetOrCreateCounter(`db_pgops{phase="clone"}`) //nolint 103 DbPgopsSplit = metrics.GetOrCreateCounter(`db_pgops{phase="split"}`) //nolint 104 DbPgopsMerge = metrics.GetOrCreateCounter(`db_pgops{phase="merge"}`) //nolint 105 DbPgopsSpill = metrics.GetOrCreateCounter(`db_pgops{phase="spill"}`) //nolint 106 DbPgopsUnspill = metrics.GetOrCreateCounter(`db_pgops{phase="unspill"}`) //nolint 107 DbPgopsWops = metrics.GetOrCreateCounter(`db_pgops{phase="wops"}`) //nolint 108 /* 109 DbPgopsPrefault = metrics.NewCounter(`db_pgops{phase="prefault"}`) //nolint 110 DbPgopsMinicore = metrics.NewCounter(`db_pgops{phase="minicore"}`) //nolint 111 DbPgopsMsync = metrics.NewCounter(`db_pgops{phase="msync"}`) //nolint 112 DbPgopsFsync = metrics.NewCounter(`db_pgops{phase="fsync"}`) //nolint 113 DbMiLastPgNo = metrics.NewCounter(`db_mi_last_pgno`) //nolint 114 115 DbGcWorkRtime = metrics.GetOrCreateSummary(`db_gc_seconds{phase="work_rtime"}`) //nolint 116 DbGcWorkRsteps = metrics.NewCounter(`db_gc{phase="work_rsteps"}`) //nolint 117 DbGcWorkRxpages = metrics.NewCounter(`db_gc{phase="work_rxpages"}`) //nolint 118 DbGcSelfRtime = metrics.GetOrCreateSummary(`db_gc_seconds{phase="self_rtime"}`) //nolint 119 DbGcSelfXtime = metrics.GetOrCreateSummary(`db_gc_seconds{phase="self_xtime"}`) //nolint 120 DbGcWorkXtime = metrics.GetOrCreateSummary(`db_gc_seconds{phase="work_xtime"}`) //nolint 121 DbGcSelfRsteps = metrics.NewCounter(`db_gc{phase="self_rsteps"}`) //nolint 122 DbGcWloops = metrics.NewCounter(`db_gc{phase="wloop"}`) //nolint 123 DbGcCoalescences = metrics.NewCounter(`db_gc{phase="coalescences"}`) //nolint 124 DbGcWipes = metrics.NewCounter(`db_gc{phase="wipes"}`) //nolint 125 DbGcFlushes = metrics.NewCounter(`db_gc{phase="flushes"}`) //nolint 126 DbGcKicks = metrics.NewCounter(`db_gc{phase="kicks"}`) //nolint 127 DbGcWorkMajflt = metrics.NewCounter(`db_gc{phase="work_majflt"}`) //nolint 128 DbGcSelfMajflt = metrics.NewCounter(`db_gc{phase="self_majflt"}`) //nolint 129 DbGcWorkCounter = metrics.NewCounter(`db_gc{phase="work_counter"}`) //nolint 130 DbGcSelfCounter = metrics.NewCounter(`db_gc{phase="self_counter"}`) //nolint 131 DbGcSelfXpages = metrics.NewCounter(`db_gc{phase="self_xpages"}`) //nolint 132 */ 133 134 //DbGcWorkPnlMergeTime = metrics.GetOrCreateSummary(`db_gc_pnl_seconds{phase="work_merge_time"}`) //nolint 135 //DbGcWorkPnlMergeVolume = metrics.NewCounter(`db_gc_pnl{phase="work_merge_volume"}`) //nolint 136 //DbGcWorkPnlMergeCalls = metrics.NewCounter(`db_gc{phase="work_merge_calls"}`) //nolint 137 //DbGcSelfPnlMergeTime = metrics.GetOrCreateSummary(`db_gc_pnl_seconds{phase="slef_merge_time"}`) //nolint 138 //DbGcSelfPnlMergeVolume = metrics.NewCounter(`db_gc_pnl{phase="self_merge_volume"}`) //nolint 139 //DbGcSelfPnlMergeCalls = metrics.NewCounter(`db_gc_pnl{phase="slef_merge_calls"}`) //nolint 140 141 GcLeafMetric = metrics.GetOrCreateCounter(`db_gc_leaf`) //nolint 142 GcOverflowMetric = metrics.GetOrCreateCounter(`db_gc_overflow`) //nolint 143 GcPagesMetric = metrics.GetOrCreateCounter(`db_gc_pages`) //nolint 144 145 ) 146 147 type DBVerbosityLvl int8 148 type Label uint8 149 150 const ( 151 ChainDB Label = 0 152 TxPoolDB Label = 1 153 SentryDB Label = 2 154 ConsensusDB Label = 3 155 DownloaderDB Label = 4 156 InMem Label = 5 157 ) 158 159 func (l Label) String() string { 160 switch l { 161 case ChainDB: 162 return "chaindata" 163 case TxPoolDB: 164 return "txpool" 165 case SentryDB: 166 return "sentry" 167 case ConsensusDB: 168 return "consensus" 169 case DownloaderDB: 170 return "downloader" 171 case InMem: 172 return "inMem" 173 default: 174 return "unknown" 175 } 176 } 177 func UnmarshalLabel(s string) Label { 178 switch s { 179 case "chaindata": 180 return ChainDB 181 case "txpool": 182 return TxPoolDB 183 case "sentry": 184 return SentryDB 185 case "consensus": 186 return ConsensusDB 187 case "downloader": 188 return DownloaderDB 189 case "inMem": 190 return InMem 191 default: 192 panic(fmt.Sprintf("unexpected label: %s", s)) 193 } 194 } 195 196 type Has interface { 197 // Has indicates whether a key exists in the database. 198 Has(table string, key []byte) (bool, error) 199 } 200 type GetPut interface { 201 Getter 202 Putter 203 } 204 type Getter interface { 205 Has 206 207 // GetOne references a readonly section of memory that must not be accessed after txn has terminated 208 GetOne(table string, key []byte) (val []byte, err error) 209 210 // ForEach iterates over entries with keys greater or equal to fromPrefix. 211 // walker is called for each eligible entry. 212 // If walker returns an error: 213 // - implementations of local db - stop 214 // - implementations of remote db - do not handle this error and may finish (send all entries to client) before error happen. 215 ForEach(table string, fromPrefix []byte, walker func(k, v []byte) error) error 216 ForPrefix(table string, prefix []byte, walker func(k, v []byte) error) error 217 ForAmount(table string, prefix []byte, amount uint32, walker func(k, v []byte) error) error 218 } 219 220 // Putter wraps the database write operations. 221 type Putter interface { 222 // Put inserts or updates a single entry. 223 Put(table string, k, v []byte) error 224 } 225 226 // Deleter wraps the database delete operations. 227 type Deleter interface { 228 // Delete removes a single entry. 229 Delete(table string, k []byte) error 230 } 231 232 type Closer interface { 233 Close() 234 } 235 236 // RoDB - Read-only version of KV. 237 type RoDB interface { 238 Closer 239 ReadOnly() bool 240 View(ctx context.Context, f func(tx Tx) error) error 241 242 // BeginRo - creates transaction 243 // tx may be discarded by .Rollback() method 244 // 245 // A transaction and its cursors must only be used by a single 246 // thread (not goroutine), and a thread may only have a single transaction at a time. 247 // It happen automatically by - because this method calls runtime.LockOSThread() inside (Rollback/Commit releases it) 248 // By this reason application code can't call runtime.UnlockOSThread() - it leads to undefined behavior. 249 // 250 // If this `parent` is non-NULL, the new transaction 251 // will be a nested transaction, with the transaction indicated by parent 252 // as its parent. Transactions may be nested to any level. A parent 253 // transaction and its cursors may not issue any other operations than 254 // Commit and Rollback while it has active child transactions. 255 BeginRo(ctx context.Context) (Tx, error) 256 AllTables() TableCfg 257 PageSize() uint64 258 } 259 260 // RwDB low-level database interface - main target is - to provide common abstraction over top of MDBX and RemoteKV. 261 // 262 // Common pattern for short-living transactions: 263 // 264 // if err := db.View(ctx, func(tx ethdb.Tx) error { 265 // ... code which uses database in transaction 266 // }); err != nil { 267 // return err 268 // } 269 // 270 // Common pattern for long-living transactions: 271 // 272 // tx, err := db.Begin() 273 // if err != nil { 274 // return err 275 // } 276 // defer tx.Rollback() 277 // 278 // ... code which uses database in transaction 279 // 280 // err := tx.Commit() 281 // if err != nil { 282 // return err 283 // } 284 type RwDB interface { 285 RoDB 286 287 Update(ctx context.Context, f func(tx RwTx) error) error 288 UpdateNosync(ctx context.Context, f func(tx RwTx) error) error 289 290 BeginRw(ctx context.Context) (RwTx, error) 291 BeginRwNosync(ctx context.Context) (RwTx, error) 292 } 293 294 type StatelessReadTx interface { 295 Getter 296 297 Commit() error // Commit all the operations of a transaction into the database. 298 Rollback() // Rollback - abandon all the operations of the transaction instead of saving them. 299 300 // ReadSequence - allows to create a linear sequence of unique positive integers for each table. 301 // Can be called for a read transaction to retrieve the current sequence value, and the increment must be zero. 302 // Sequence changes become visible outside the current write transaction after it is committed, and discarded on abort. 303 // Starts from 0. 304 ReadSequence(table string) (uint64, error) 305 306 BucketSize(table string) (uint64, error) 307 } 308 309 type StatelessWriteTx interface { 310 Putter 311 Deleter 312 313 /* 314 // if need N id's: 315 baseId, err := tx.IncrementSequence(bucket, N) 316 if err != nil { 317 return err 318 } 319 for i := 0; i < N; i++ { // if N == 0, it will work as expected 320 id := baseId + i 321 // use id 322 } 323 324 325 // or if need only 1 id: 326 id, err := tx.IncrementSequence(bucket, 1) 327 if err != nil { 328 return err 329 } 330 // use id 331 */ 332 IncrementSequence(table string, amount uint64) (uint64, error) 333 Append(table string, k, v []byte) error 334 AppendDup(table string, k, v []byte) error 335 } 336 337 type StatelessRwTx interface { 338 StatelessReadTx 339 StatelessWriteTx 340 } 341 342 // Tx 343 // WARNING: 344 // - Tx is not threadsafe and may only be used in the goroutine that created it 345 // - ReadOnly transactions do not lock goroutine to thread, RwTx does 346 type Tx interface { 347 StatelessReadTx 348 BucketMigratorRO 349 350 // ID returns the identifier associated with this transaction. For a 351 // read-only transaction, this corresponds to the snapshot being read; 352 // concurrent readers will frequently have the same transaction ID. 353 ViewID() uint64 354 355 // Cursor - creates cursor object on top of given bucket. Type of cursor - depends on bucket configuration. 356 // If bucket was created with mdbx.DupSort flag, then cursor with interface CursorDupSort created 357 // Otherwise - object of interface Cursor created 358 // 359 // Cursor, also provides a grain of magic - it can use a declarative configuration - and automatically break 360 // long keys into DupSort key/values. See docs for `bucket.go:TableCfgItem` 361 Cursor(table string) (Cursor, error) 362 CursorDupSort(table string) (CursorDupSort, error) // CursorDupSort - can be used if bucket has mdbx.DupSort flag 363 364 DBSize() (uint64, error) 365 366 // --- High-Level methods: 1request -> stream of server-side pushes --- 367 368 // Range [from, to) 369 // Range(from, nil) means [from, EndOfTable) 370 // Range(nil, to) means [StartOfTable, to) 371 Range(table string, fromPrefix, toPrefix []byte) (iter.KV, error) 372 // Stream is like Range, but for requesting huge data (Example: full table scan). Client can't stop it. 373 //Stream(table string, fromPrefix, toPrefix []byte) (iter.KV, error) 374 // RangeAscend - like Range [from, to) but also allow pass Limit parameters 375 // Limit -1 means Unlimited 376 RangeAscend(table string, fromPrefix, toPrefix []byte, limit int) (iter.KV, error) 377 //StreamAscend(table string, fromPrefix, toPrefix []byte, limit int) (iter.KV, error) 378 // RangeDescend - is like Range [from, to), but expecing `from`<`to` 379 // example: RangeDescend("Table", "B", "A", -1) 380 RangeDescend(table string, fromPrefix, toPrefix []byte, limit int) (iter.KV, error) 381 //StreamDescend(table string, fromPrefix, toPrefix []byte, limit int) (iter.KV, error) 382 // Prefix - is exactly Range(Table, prefix, kv.NextSubtree(prefix)) 383 Prefix(table string, prefix []byte) (iter.KV, error) 384 385 // RangeDupSort - like Range but for fixed single key and iterating over range of values 386 RangeDupSort(table string, key []byte, fromPrefix, toPrefix []byte, asc order.By, limit int) (iter.KV, error) 387 388 // --- High-Level methods: 1request -> 1page of values in response -> send next page request --- 389 // Paginate(table string, fromPrefix, toPrefix []byte) (PairsStream, error) 390 391 // --- High-Level deprecated methods --- 392 393 ForEach(table string, fromPrefix []byte, walker func(k, v []byte) error) error 394 ForPrefix(table string, prefix []byte, walker func(k, v []byte) error) error 395 ForAmount(table string, prefix []byte, amount uint32, walker func(k, v []byte) error) error 396 } 397 398 // RwTx 399 // 400 // WARNING: 401 // - RwTx is not threadsafe and may only be used in the goroutine that created it. 402 // - ReadOnly transactions do not lock goroutine to thread, RwTx does 403 // - User Can't call runtime.LockOSThread/runtime.UnlockOSThread in same goroutine until RwTx Commit/Rollback 404 type RwTx interface { 405 Tx 406 StatelessWriteTx 407 BucketMigrator 408 409 RwCursor(table string) (RwCursor, error) 410 RwCursorDupSort(table string) (RwCursorDupSort, error) 411 412 // CollectMetrics - does collect all DB-related and Tx-related metrics 413 // this method exists only in RwTx to avoid concurrency 414 CollectMetrics() 415 } 416 417 type BucketMigratorRO interface { 418 ListBuckets() ([]string, error) 419 } 420 421 // BucketMigrator used for buckets migration, don't use it in usual app code 422 type BucketMigrator interface { 423 BucketMigratorRO 424 DropBucket(string) error 425 CreateBucket(string) error 426 ExistsBucket(string) (bool, error) 427 ClearBucket(string) error 428 } 429 430 // Cursor - class for navigating through a database 431 // CursorDupSort are inherit this class 432 // 433 // If methods (like First/Next/Seek) return error, then returned key SHOULD not be nil (can be []byte{} for example). 434 // Then looping code will look as: 435 // c := kv.Cursor(bucketName) 436 // 437 // for k, v, err := c.First(); k != nil; k, v, err = c.Next() { 438 // if err != nil { 439 // return err 440 // } 441 // ... logic 442 // } 443 type Cursor interface { 444 First() ([]byte, []byte, error) // First - position at first key/data item 445 Seek(seek []byte) ([]byte, []byte, error) // Seek - position at first key greater than or equal to specified key 446 SeekExact(key []byte) ([]byte, []byte, error) // SeekExact - position at exact matching key if exists 447 Next() ([]byte, []byte, error) // Next - position at next key/value (can iterate over DupSort key/values automatically) 448 Prev() ([]byte, []byte, error) // Prev - position at previous key 449 Last() ([]byte, []byte, error) // Last - position at last key and last possible value 450 Current() ([]byte, []byte, error) // Current - return key/data at current cursor position 451 452 Count() (uint64, error) // Count - fast way to calculate amount of keys in bucket. It counts all keys even if Prefix was set. 453 454 Close() 455 } 456 457 type RwCursor interface { 458 Cursor 459 460 Put(k, v []byte) error // Put - based on order 461 Append(k []byte, v []byte) error // Append - append the given key/data pair to the end of the database. This option allows fast bulk loading when keys are already known to be in the correct order. 462 Delete(k []byte) error // Delete - short version of SeekExact+DeleteCurrent or SeekBothExact+DeleteCurrent 463 464 // DeleteCurrent This function deletes the key/data pair to which the cursor refers. 465 // This does not invalidate the cursor, so operations such as MDB_NEXT 466 // can still be used on it. 467 // Both MDB_NEXT and MDB_GET_CURRENT will return the same record after 468 // this operation. 469 DeleteCurrent() error 470 } 471 472 // CursorDupSort 473 // 474 // Example: 475 // 476 // for k, v, err = cursor.First(); k != nil; k, v, err = cursor.NextNoDup() { 477 // if err != nil { 478 // return err 479 // } 480 // for ; v != nil; _, v, err = cursor.NextDup() { 481 // if err != nil { 482 // return err 483 // } 484 // 485 // } 486 // } 487 type CursorDupSort interface { 488 Cursor 489 490 // SeekBothExact - 491 // second parameter can be nil only if searched key has no duplicates, or return error 492 SeekBothExact(key, value []byte) ([]byte, []byte, error) 493 SeekBothRange(key, value []byte) ([]byte, error) // SeekBothRange - exact match of the key, but range match of the value 494 FirstDup() ([]byte, error) // FirstDup - position at first data item of current key 495 NextDup() ([]byte, []byte, error) // NextDup - position at next data item of current key 496 NextNoDup() ([]byte, []byte, error) // NextNoDup - position at first data item of next key 497 PrevDup() ([]byte, []byte, error) 498 PrevNoDup() ([]byte, []byte, error) 499 LastDup() ([]byte, error) // LastDup - position at last data item of current key 500 501 CountDuplicates() (uint64, error) // CountDuplicates - number of duplicates for the current key 502 } 503 504 type RwCursorDupSort interface { 505 CursorDupSort 506 RwCursor 507 508 PutNoDupData(key, value []byte) error // PutNoDupData - inserts key without dupsort 509 DeleteCurrentDuplicates() error // DeleteCurrentDuplicates - deletes all of the data items for the current key 510 DeleteExact(k1, k2 []byte) error // DeleteExact - delete 1 value from given key 511 AppendDup(key, value []byte) error // AppendDup - same as Append, but for sorted dup data 512 } 513 514 // ---- Temporal part 515 516 type ( 517 Domain string 518 History string 519 InvertedIdx string 520 ) 521 522 type TemporalTx interface { 523 Tx 524 DomainGet(name Domain, k, k2 []byte) (v []byte, ok bool, err error) 525 DomainGetAsOf(name Domain, k, k2 []byte, ts uint64) (v []byte, ok bool, err error) 526 HistoryGet(name History, k []byte, ts uint64) (v []byte, ok bool, err error) 527 528 // IndexRange - return iterator over range of inverted index for given key `k` 529 // Asc semantic: [from, to) AND from > to 530 // Desc semantic: [from, to) AND from < to 531 // Limit -1 means Unlimited 532 // from -1, to -1 means unbounded (StartOfTable, EndOfTable) 533 // Example: IndexRange("IndexName", 10, 5, order.Desc, -1) 534 // Example: IndexRange("IndexName", -1, -1, order.Asc, 10) 535 IndexRange(name InvertedIdx, k []byte, fromTs, toTs int, asc order.By, limit int) (timestamps iter.U64, err error) 536 HistoryRange(name History, fromTs, toTs int, asc order.By, limit int) (it iter.KV, err error) 537 DomainRange(name Domain, fromKey, toKey []byte, ts uint64, asc order.By, limit int) (it iter.KV, err error) 538 }