github.com/ledgerwatch/erigon-lib@v1.0.0/kv/iter/iter.go (about) 1 /* 2 Copyright 2021 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 iter 18 19 import ( 20 "bytes" 21 22 "github.com/ledgerwatch/erigon-lib/kv/order" 23 "golang.org/x/exp/constraints" 24 "golang.org/x/exp/slices" 25 ) 26 27 type Closer interface { 28 Close() 29 } 30 31 var ( 32 EmptyU64 = &EmptyUnary[uint64]{} 33 EmptyKV = &EmptyDual[[]byte, []byte]{} 34 ) 35 36 type ( 37 EmptyUnary[T any] struct{} 38 EmptyDual[K, V any] struct{} 39 ) 40 41 func (EmptyUnary[T]) HasNext() bool { return false } 42 func (EmptyUnary[T]) Next() (v T, err error) { return v, err } 43 func (EmptyDual[K, V]) HasNext() bool { return false } 44 func (EmptyDual[K, V]) Next() (k K, v V, err error) { return k, v, err } 45 46 type ArrStream[V any] struct { 47 arr []V 48 i int 49 } 50 51 func ReverseArray[V any](arr []V) *ArrStream[V] { 52 arr = slices.Clone(arr) 53 for i, j := 0, len(arr)-1; i < j; i, j = i+1, j-1 { 54 arr[i], arr[j] = arr[j], arr[i] 55 } 56 return Array(arr) 57 } 58 func Array[V any](arr []V) *ArrStream[V] { return &ArrStream[V]{arr: arr} } 59 func (it *ArrStream[V]) HasNext() bool { return it.i < len(it.arr) } 60 func (it *ArrStream[V]) Close() {} 61 func (it *ArrStream[V]) Next() (V, error) { 62 v := it.arr[it.i] 63 it.i++ 64 return v, nil 65 } 66 func (it *ArrStream[V]) NextBatch() ([]V, error) { 67 v := it.arr[it.i:] 68 it.i = len(it.arr) 69 return v, nil 70 } 71 72 func Range[T constraints.Integer](from, to T) *RangeIter[T] { 73 if from == to { 74 to++ 75 } 76 return &RangeIter[T]{i: from, to: to} 77 } 78 79 type RangeIter[T constraints.Integer] struct { 80 i, to T 81 } 82 83 func (it *RangeIter[T]) HasNext() bool { return it.i < it.to } 84 func (it *RangeIter[T]) Close() {} 85 func (it *RangeIter[T]) Next() (T, error) { 86 v := it.i 87 it.i++ 88 return v, nil 89 } 90 91 // UnionKVIter - merge 2 kv.Pairs streams to 1 in lexicographically order 92 // 1-st stream has higher priority - when 2 streams return same key 93 type UnionKVIter struct { 94 x, y KV 95 xHasNext, yHasNext bool 96 xNextK, xNextV []byte 97 yNextK, yNextV []byte 98 limit int 99 err error 100 } 101 102 func UnionKV(x, y KV, limit int) KV { 103 if x == nil && y == nil { 104 return EmptyKV 105 } 106 if x == nil { 107 return y 108 } 109 if y == nil { 110 return x 111 } 112 m := &UnionKVIter{x: x, y: y, limit: limit} 113 m.advanceX() 114 m.advanceY() 115 return m 116 } 117 func (m *UnionKVIter) HasNext() bool { 118 return m.err != nil || (m.limit != 0 && m.xHasNext) || (m.limit != 0 && m.yHasNext) 119 } 120 func (m *UnionKVIter) advanceX() { 121 if m.err != nil { 122 return 123 } 124 m.xHasNext = m.x.HasNext() 125 if m.xHasNext { 126 m.xNextK, m.xNextV, m.err = m.x.Next() 127 } 128 } 129 func (m *UnionKVIter) advanceY() { 130 if m.err != nil { 131 return 132 } 133 m.yHasNext = m.y.HasNext() 134 if m.yHasNext { 135 m.yNextK, m.yNextV, m.err = m.y.Next() 136 } 137 } 138 func (m *UnionKVIter) Next() ([]byte, []byte, error) { 139 if m.err != nil { 140 return nil, nil, m.err 141 } 142 m.limit-- 143 if m.xHasNext && m.yHasNext { 144 cmp := bytes.Compare(m.xNextK, m.yNextK) 145 if cmp < 0 { 146 k, v, err := m.xNextK, m.xNextV, m.err 147 m.advanceX() 148 return k, v, err 149 } else if cmp == 0 { 150 k, v, err := m.xNextK, m.xNextV, m.err 151 m.advanceX() 152 m.advanceY() 153 return k, v, err 154 } 155 k, v, err := m.yNextK, m.yNextV, m.err 156 m.advanceY() 157 return k, v, err 158 } 159 if m.xHasNext { 160 k, v, err := m.xNextK, m.xNextV, m.err 161 m.advanceX() 162 return k, v, err 163 } 164 k, v, err := m.yNextK, m.yNextV, m.err 165 m.advanceY() 166 return k, v, err 167 } 168 169 // func (m *UnionKVIter) ToArray() (keys, values [][]byte, err error) { return ToKVArray(m) } 170 func (m *UnionKVIter) Close() { 171 if x, ok := m.x.(Closer); ok { 172 x.Close() 173 } 174 if y, ok := m.y.(Closer); ok { 175 y.Close() 176 } 177 } 178 179 // UnionUnary 180 type UnionUnary[T constraints.Ordered] struct { 181 x, y Unary[T] 182 asc bool 183 xHas, yHas bool 184 xNextK, yNextK T 185 err error 186 limit int 187 } 188 189 func Union[T constraints.Ordered](x, y Unary[T], asc order.By, limit int) Unary[T] { 190 if x == nil && y == nil { 191 return &EmptyUnary[T]{} 192 } 193 if x == nil { 194 return y 195 } 196 if y == nil { 197 return x 198 } 199 if !x.HasNext() { 200 return y 201 } 202 if !y.HasNext() { 203 return x 204 } 205 m := &UnionUnary[T]{x: x, y: y, asc: bool(asc), limit: limit} 206 m.advanceX() 207 m.advanceY() 208 return m 209 } 210 211 func (m *UnionUnary[T]) HasNext() bool { 212 return m.err != nil || (m.limit != 0 && m.xHas) || (m.limit != 0 && m.yHas) 213 } 214 func (m *UnionUnary[T]) advanceX() { 215 if m.err != nil { 216 return 217 } 218 m.xHas = m.x.HasNext() 219 if m.xHas { 220 m.xNextK, m.err = m.x.Next() 221 } 222 } 223 func (m *UnionUnary[T]) advanceY() { 224 if m.err != nil { 225 return 226 } 227 m.yHas = m.y.HasNext() 228 if m.yHas { 229 m.yNextK, m.err = m.y.Next() 230 } 231 } 232 233 func (m *UnionUnary[T]) less() bool { 234 return (m.asc && m.xNextK < m.yNextK) || (!m.asc && m.xNextK > m.yNextK) 235 } 236 237 func (m *UnionUnary[T]) Next() (res T, err error) { 238 if m.err != nil { 239 return res, m.err 240 } 241 m.limit-- 242 if m.xHas && m.yHas { 243 if m.less() { 244 k, err := m.xNextK, m.err 245 m.advanceX() 246 return k, err 247 } else if m.xNextK == m.yNextK { 248 k, err := m.xNextK, m.err 249 m.advanceX() 250 m.advanceY() 251 return k, err 252 } 253 k, err := m.yNextK, m.err 254 m.advanceY() 255 return k, err 256 } 257 if m.xHas { 258 k, err := m.xNextK, m.err 259 m.advanceX() 260 return k, err 261 } 262 k, err := m.yNextK, m.err 263 m.advanceY() 264 return k, err 265 } 266 func (m *UnionUnary[T]) Close() { 267 if x, ok := m.x.(Closer); ok { 268 x.Close() 269 } 270 if y, ok := m.y.(Closer); ok { 271 y.Close() 272 } 273 } 274 275 // IntersectIter 276 type IntersectIter[T constraints.Ordered] struct { 277 x, y Unary[T] 278 xHasNext, yHasNext bool 279 xNextK, yNextK T 280 limit int 281 err error 282 } 283 284 func Intersect[T constraints.Ordered](x, y Unary[T], limit int) Unary[T] { 285 if x == nil || y == nil || !x.HasNext() || !y.HasNext() { 286 return &EmptyUnary[T]{} 287 } 288 m := &IntersectIter[T]{x: x, y: y, limit: limit} 289 m.advance() 290 return m 291 } 292 func (m *IntersectIter[T]) HasNext() bool { 293 return m.err != nil || (m.limit != 0 && m.xHasNext && m.yHasNext) 294 } 295 func (m *IntersectIter[T]) advance() { 296 m.advanceX() 297 m.advanceY() 298 for m.xHasNext && m.yHasNext { 299 if m.err != nil { 300 break 301 } 302 if m.xNextK < m.yNextK { 303 m.advanceX() 304 continue 305 } else if m.xNextK == m.yNextK { 306 return 307 } else { 308 m.advanceY() 309 continue 310 } 311 } 312 m.xHasNext = false 313 } 314 315 func (m *IntersectIter[T]) advanceX() { 316 if m.err != nil { 317 return 318 } 319 m.xHasNext = m.x.HasNext() 320 if m.xHasNext { 321 m.xNextK, m.err = m.x.Next() 322 } 323 } 324 func (m *IntersectIter[T]) advanceY() { 325 if m.err != nil { 326 return 327 } 328 m.yHasNext = m.y.HasNext() 329 if m.yHasNext { 330 m.yNextK, m.err = m.y.Next() 331 } 332 } 333 func (m *IntersectIter[T]) Next() (T, error) { 334 if m.err != nil { 335 return m.xNextK, m.err 336 } 337 m.limit-- 338 k, err := m.xNextK, m.err 339 m.advance() 340 return k, err 341 } 342 func (m *IntersectIter[T]) Close() { 343 if x, ok := m.x.(Closer); ok { 344 x.Close() 345 } 346 if y, ok := m.y.(Closer); ok { 347 y.Close() 348 } 349 } 350 351 // TransformDualIter - analog `map` (in terms of map-filter-reduce pattern) 352 type TransformDualIter[K, V any] struct { 353 it Dual[K, V] 354 transform func(K, V) (K, V, error) 355 } 356 357 func TransformDual[K, V any](it Dual[K, V], transform func(K, V) (K, V, error)) *TransformDualIter[K, V] { 358 return &TransformDualIter[K, V]{it: it, transform: transform} 359 } 360 func (m *TransformDualIter[K, V]) HasNext() bool { return m.it.HasNext() } 361 func (m *TransformDualIter[K, V]) Next() (K, V, error) { 362 k, v, err := m.it.Next() 363 if err != nil { 364 return k, v, err 365 } 366 return m.transform(k, v) 367 } 368 func (m *TransformDualIter[K, v]) Close() { 369 if x, ok := m.it.(Closer); ok { 370 x.Close() 371 } 372 } 373 374 type TransformKV2U64Iter[K, V []byte] struct { 375 it KV 376 transform func(K, V) (uint64, error) 377 } 378 379 func TransformKV2U64[K, V []byte](it KV, transform func(K, V) (uint64, error)) *TransformKV2U64Iter[K, V] { 380 return &TransformKV2U64Iter[K, V]{it: it, transform: transform} 381 } 382 func (m *TransformKV2U64Iter[K, V]) HasNext() bool { return m.it.HasNext() } 383 func (m *TransformKV2U64Iter[K, V]) Next() (uint64, error) { 384 k, v, err := m.it.Next() 385 if err != nil { 386 return 0, err 387 } 388 return m.transform(k, v) 389 } 390 func (m *TransformKV2U64Iter[K, v]) Close() { 391 if x, ok := m.it.(Closer); ok { 392 x.Close() 393 } 394 } 395 396 // FilterDualIter - analog `map` (in terms of map-filter-reduce pattern) 397 // please avoid reading from Disk/DB more elements and then filter them. Better 398 // push-down filter conditions to lower-level iterator to reduce disk reads amount. 399 type FilterDualIter[K, V any] struct { 400 it Dual[K, V] 401 filter func(K, V) bool 402 hasNext bool 403 err error 404 nextK K 405 nextV V 406 } 407 408 func FilterKV(it KV, filter func(k, v []byte) bool) *FilterDualIter[[]byte, []byte] { 409 return FilterDual[[]byte, []byte](it, filter) 410 } 411 func FilterDual[K, V any](it Dual[K, V], filter func(K, V) bool) *FilterDualIter[K, V] { 412 i := &FilterDualIter[K, V]{it: it, filter: filter} 413 i.advance() 414 return i 415 } 416 func (m *FilterDualIter[K, V]) advance() { 417 if m.err != nil { 418 return 419 } 420 m.hasNext = false 421 for m.it.HasNext() { 422 // create new variables, to avoid leaking outside of loop 423 key, val, err := m.it.Next() 424 if err != nil { 425 m.err = err 426 return 427 } 428 if m.filter(key, val) { 429 m.hasNext = true 430 m.nextK, m.nextV = key, val 431 break 432 } 433 } 434 } 435 func (m *FilterDualIter[K, V]) HasNext() bool { return m.err != nil || m.hasNext } 436 func (m *FilterDualIter[K, V]) Next() (k K, v V, err error) { 437 k, v, err = m.nextK, m.nextV, m.err 438 m.advance() 439 return k, v, err 440 } 441 func (m *FilterDualIter[K, v]) Close() { 442 if x, ok := m.it.(Closer); ok { 443 x.Close() 444 } 445 } 446 447 // FilterUnaryIter - analog `map` (in terms of map-filter-reduce pattern) 448 // please avoid reading from Disk/DB more elements and then filter them. Better 449 // push-down filter conditions to lower-level iterator to reduce disk reads amount. 450 type FilterUnaryIter[T any] struct { 451 it Unary[T] 452 filter func(T) bool 453 hasNext bool 454 err error 455 nextK T 456 } 457 458 func FilterU64(it U64, filter func(k uint64) bool) *FilterUnaryIter[uint64] { 459 return FilterUnary[uint64](it, filter) 460 } 461 func FilterUnary[T any](it Unary[T], filter func(T) bool) *FilterUnaryIter[T] { 462 i := &FilterUnaryIter[T]{it: it, filter: filter} 463 i.advance() 464 return i 465 } 466 func (m *FilterUnaryIter[T]) advance() { 467 if m.err != nil { 468 return 469 } 470 m.hasNext = false 471 for m.it.HasNext() { 472 // create new variables, to avoid leaking outside of loop 473 key, err := m.it.Next() 474 if err != nil { 475 m.err = err 476 return 477 } 478 if m.filter(key) { 479 m.hasNext, m.nextK = true, key 480 break 481 } 482 } 483 } 484 func (m *FilterUnaryIter[T]) HasNext() bool { return m.err != nil || m.hasNext } 485 func (m *FilterUnaryIter[T]) Next() (k T, err error) { 486 k, err = m.nextK, m.err 487 m.advance() 488 return k, err 489 } 490 func (m *FilterUnaryIter[T]) Close() { 491 if x, ok := m.it.(Closer); ok { 492 x.Close() 493 } 494 } 495 496 // PaginatedIter - for remote-list pagination 497 // 498 // Rationale: If an API does not support pagination from the start, supporting it later is troublesome because adding pagination breaks the API's behavior. Clients that are unaware that the API now uses pagination could incorrectly assume that they received a complete result, when in fact they only received the first page. 499 // 500 // To support pagination (returning list results in pages) in a List method, the API shall: 501 // - The client uses this field to request a specific page of the list results. 502 // - define an int32 field page_size in the List method's request message. Clients use this field to specify the maximum number of results to be returned by the server. The server may further constrain the maximum number of results returned in a single page. If the page_size is 0, the server will decide the number of results to be returned. 503 // - define a string field next_page_token in the List method's response message. This field represents the pagination token to retrieve the next page of results. If the value is "", it means no further results for the request. 504 // 505 // see: https://cloud.google.com/apis/design/design_patterns 506 type Paginated[T any] struct { 507 arr []T 508 i int 509 err error 510 nextPage NextPageUnary[T] 511 nextPageToken string 512 initialized bool 513 } 514 515 func Paginate[T any](f NextPageUnary[T]) *Paginated[T] { return &Paginated[T]{nextPage: f} } 516 func (it *Paginated[T]) HasNext() bool { 517 if it.err != nil || it.i < len(it.arr) { 518 return true 519 } 520 if it.initialized && it.nextPageToken == "" { 521 return false 522 } 523 it.initialized = true 524 it.i = 0 525 it.arr, it.nextPageToken, it.err = it.nextPage(it.nextPageToken) 526 return it.err != nil || it.i < len(it.arr) 527 } 528 func (it *Paginated[T]) Close() {} 529 func (it *Paginated[T]) Next() (v T, err error) { 530 if it.err != nil { 531 return v, it.err 532 } 533 v = it.arr[it.i] 534 it.i++ 535 return v, nil 536 } 537 538 type PaginatedDual[K, V any] struct { 539 keys []K 540 values []V 541 i int 542 err error 543 nextPage NextPageDual[K, V] 544 nextPageToken string 545 initialized bool 546 } 547 548 func PaginateDual[K, V any](f NextPageDual[K, V]) *PaginatedDual[K, V] { 549 return &PaginatedDual[K, V]{nextPage: f} 550 } 551 func (it *PaginatedDual[K, V]) HasNext() bool { 552 if it.err != nil || it.i < len(it.keys) { 553 return true 554 } 555 if it.initialized && it.nextPageToken == "" { 556 return false 557 } 558 it.initialized = true 559 it.i = 0 560 it.keys, it.values, it.nextPageToken, it.err = it.nextPage(it.nextPageToken) 561 return it.err != nil || it.i < len(it.keys) 562 } 563 func (it *PaginatedDual[K, V]) Close() {} 564 func (it *PaginatedDual[K, V]) Next() (k K, v V, err error) { 565 if it.err != nil { 566 return k, v, it.err 567 } 568 k, v = it.keys[it.i], it.values[it.i] 569 it.i++ 570 return k, v, nil 571 }