github.com/zuoyebang/bitalosdb@v1.1.1-0.20240516111551-79a8c4d8ce20/bitpage/array_table.go (about) 1 // Copyright 2021 The Bitalosdb author(hustxrb@163.com) and other contributors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package bitpage 16 17 import ( 18 "bytes" 19 "encoding/binary" 20 "errors" 21 "fmt" 22 "os" 23 "sort" 24 25 "github.com/golang/snappy" 26 "github.com/zuoyebang/bitalosdb/internal/base" 27 "github.com/zuoyebang/bitalosdb/internal/bindex" 28 "github.com/zuoyebang/bitalosdb/internal/bytepools" 29 "github.com/zuoyebang/bitalosdb/internal/cache/lrucache" 30 "github.com/zuoyebang/bitalosdb/internal/consts" 31 "github.com/zuoyebang/bitalosdb/internal/hash" 32 ) 33 34 const ( 35 atVersionDefault uint16 = iota + 1 36 atVersionPrefixCompress 37 atVersionBlockCompress 38 atVersionPrefixBlockCompress 39 atVersionBitrieCompress 40 ) 41 42 const ( 43 atHeaderSize = 18 44 atHeaderOffset = tableDataOffset 45 atDataOffset = atHeaderOffset + atHeaderSize 46 47 itemOffsetSize = 4 48 itemHeaderLen = 2 49 itemSharedMin = 0 50 itemSharedMax = 255 51 itemSharedRestart = 254 52 itemSharedMinLength = 6 53 ) 54 55 type arrayTable struct { 56 tbl *table 57 filename string 58 header *atHeader 59 block *pageBlock 60 blockSize uint32 61 blockCache *lrucache.LruCache 62 cacheID uint64 63 useMapIndex bool 64 itemsOffset []uint32 65 intIndex []byte 66 bitrieIndex *Bitrie 67 mapIndex *bindex.HashIndex 68 size uint32 69 num int 70 compressedBuf []byte 71 prevKey []byte 72 prevValue []byte 73 prevHasShared bool 74 sharedKey []byte 75 sharedNum int 76 } 77 78 type atHeader struct { 79 version uint16 80 num uint32 81 dataOffset uint32 82 intIndexOffset uint32 83 mapIndexOffset uint32 84 } 85 86 type atOptions struct { 87 useMapIndex bool 88 usePrefixCompress bool 89 useBlockCompress bool 90 useBitrieCompress bool 91 blockSize uint32 92 } 93 94 type atCacheOptions struct { 95 cache *lrucache.LruCache 96 id uint64 97 } 98 99 func checkArrayTable(obj interface{}) { 100 s := obj.(*arrayTable) 101 if s.tbl != nil { 102 fmt.Fprintf(os.Stderr, "arrayTable(%s) buffer was not freed\n", s.tbl.path) 103 os.Exit(1) 104 } 105 } 106 107 func newArrayTable(path string, opts *atOptions, cacheOpts *atCacheOptions) (*arrayTable, error) { 108 tbl, err := openTable(path, defaultTableOptions) 109 if err != nil { 110 return nil, err 111 } 112 113 at := &arrayTable{ 114 tbl: tbl, 115 filename: base.GetFilePathBase(path), 116 blockSize: opts.blockSize, 117 blockCache: cacheOpts.cache, 118 cacheID: cacheOpts.id, 119 useMapIndex: opts.useMapIndex, 120 num: 0, 121 prevKey: nil, 122 prevValue: nil, 123 prevHasShared: false, 124 sharedKey: nil, 125 sharedNum: 0, 126 } 127 128 var headerOffset uint32 129 headerOffset, err = at.tbl.alloc(atHeaderSize) 130 if err != nil { 131 return nil, err 132 } 133 if headerOffset != atHeaderOffset { 134 return nil, errors.New("tblSize is not large enough to hold the arrayTable header") 135 } 136 137 at.header = &atHeader{ 138 dataOffset: atDataOffset, 139 version: getAtVersionByOpts(opts), 140 } 141 142 if opts.useBlockCompress || opts.useBitrieCompress { 143 at.useMapIndex = false 144 } 145 146 if opts.useBitrieCompress { 147 at.bitrieIndex = NewBitrie() 148 at.bitrieIndex.InitWriter() 149 } else { 150 at.itemsOffset = make([]uint32, 0, 1<<20) 151 } 152 153 if at.useMapIndex { 154 at.mapIndex = bindex.NewHashIndex(true) 155 at.mapIndex.InitWriter() 156 } 157 158 return at, nil 159 } 160 161 func openArrayTable(path string, cacheOpts *atCacheOptions) (*arrayTable, error) { 162 tbl, err := openTable(path, &tableOptions{openType: tableReadMmap}) 163 if err != nil { 164 return nil, err 165 } 166 167 at := &arrayTable{ 168 tbl: tbl, 169 filename: base.GetFilePathBase(path), 170 blockCache: cacheOpts.cache, 171 cacheID: cacheOpts.id, 172 } 173 174 at.readHeader() 175 at.num = int(at.header.num) 176 at.size = at.tbl.Size() 177 178 if at.header.version == atVersionBitrieCompress { 179 at.bitrieIndex = NewBitrie() 180 } else if at.header.mapIndexOffset > 0 { 181 at.useMapIndex = true 182 at.mapIndex = bindex.NewHashIndex(true) 183 } 184 185 at.dataIntBuffer() 186 187 return at, nil 188 } 189 190 func getAtVersionByOpts(opts *atOptions) uint16 { 191 var version uint16 192 if opts.useBitrieCompress { 193 version = atVersionBitrieCompress 194 } else if opts.usePrefixCompress { 195 if opts.useBlockCompress { 196 version = atVersionPrefixBlockCompress 197 } else { 198 version = atVersionPrefixCompress 199 } 200 } else { 201 if opts.useBlockCompress { 202 version = atVersionBlockCompress 203 } else { 204 version = atVersionDefault 205 } 206 } 207 return version 208 } 209 210 func (a *arrayTable) writeHeader() { 211 buf := a.tbl.getBytes(atHeaderOffset, atHeaderSize) 212 binary.BigEndian.PutUint16(buf[0:2], a.header.version) 213 binary.BigEndian.PutUint32(buf[2:6], a.header.num) 214 binary.BigEndian.PutUint32(buf[6:10], a.header.dataOffset) 215 binary.BigEndian.PutUint32(buf[10:14], a.header.intIndexOffset) 216 binary.BigEndian.PutUint32(buf[14:18], a.header.mapIndexOffset) 217 } 218 219 func (a *arrayTable) readHeader() { 220 buf := a.tbl.getBytes(atHeaderOffset, atHeaderSize) 221 a.header = &atHeader{} 222 a.header.version = binary.BigEndian.Uint16(buf[0:2]) 223 a.header.num = binary.BigEndian.Uint32(buf[2:6]) 224 a.header.dataOffset = binary.BigEndian.Uint32(buf[6:10]) 225 a.header.intIndexOffset = binary.BigEndian.Uint32(buf[10:14]) 226 a.header.mapIndexOffset = binary.BigEndian.Uint32(buf[14:18]) 227 } 228 229 func (a *arrayTable) dataIntBuffer() { 230 if a.header.version == atVersionBitrieCompress { 231 a.bitrieIndex.SetReader(a.tbl.getBytes(0, a.size), atDataOffset) 232 } else { 233 a.intIndex = a.tbl.getBytes(a.header.intIndexOffset, a.getIntIndexSize()) 234 } 235 236 if a.useMapIndex { 237 a.mapIndex.SetReader(a.tbl.getBytes(a.header.mapIndexOffset, a.size-a.header.mapIndexOffset)) 238 } 239 } 240 241 func (a *arrayTable) getVersion() uint32 { 242 return uint32(a.header.version) 243 } 244 245 func (a *arrayTable) getIntIndexSize() uint32 { 246 return uint32(a.num * itemOffsetSize) 247 } 248 249 func (a *arrayTable) writeSharedInternal(shared int) (uint32, error) { 250 var keySize uint32 251 252 if !a.prevHasShared { 253 if shared >= itemSharedMinLength { 254 keySize = uint32(len(a.prevKey)) + 3 255 } else { 256 keySize = uint32(len(a.prevKey)) + 1 257 } 258 } else { 259 keySize = uint32(len(a.prevKey[len(a.sharedKey):])) + 1 260 } 261 262 valueSize := uint32(len(a.prevValue)) 263 sz := keySize + valueSize + itemHeaderLen 264 265 offset, err := a.tbl.alloc(sz) 266 if err != nil { 267 return 0, err 268 } 269 270 a.itemsOffset = append(a.itemsOffset, offset) 271 itemBuf := a.tbl.getBytes(offset, sz) 272 binary.BigEndian.PutUint16(itemBuf[0:itemHeaderLen], uint16(keySize)) 273 274 if !a.prevHasShared { 275 if shared >= itemSharedMinLength { 276 itemBuf[itemHeaderLen] = itemSharedMin 277 binary.BigEndian.PutUint16(itemBuf[itemHeaderLen+1:itemHeaderLen+3], uint16(len(a.sharedKey))) 278 copy(itemBuf[itemHeaderLen+3:itemHeaderLen+keySize], a.prevKey) 279 } else { 280 itemBuf[itemHeaderLen] = itemSharedMax 281 copy(itemBuf[itemHeaderLen+1:itemHeaderLen+keySize], a.prevKey) 282 } 283 } else { 284 itemBuf[itemHeaderLen] = uint8(a.num - a.sharedNum) 285 copy(itemBuf[itemHeaderLen+1:itemHeaderLen+keySize], a.prevKey[len(a.sharedKey):]) 286 } 287 288 copy(itemBuf[itemHeaderLen+keySize:sz], a.prevValue) 289 290 a.num++ 291 292 if a.useMapIndex { 293 a.mapIndex.Add(hash.Crc32(a.prevKey), uint32(a.num)) 294 } 295 296 return sz, nil 297 } 298 299 func (a *arrayTable) writeItem(key, value []byte) (uint32, error) { 300 switch a.header.version { 301 case atVersionPrefixCompress: 302 return a.writeItemPrefixCompress(key, value) 303 case atVersionBlockCompress, atVersionPrefixBlockCompress: 304 return a.writeItemBlockCompress(key, value) 305 case atVersionBitrieCompress: 306 return a.writeItemBitrieCompress(key, value) 307 } 308 309 return a.writeItemDefault(key, value) 310 } 311 312 func (a *arrayTable) writeItemDefault(key, value []byte) (uint32, error) { 313 keySize := uint32(len(key)) 314 valueSize := uint32(len(value)) 315 316 sz := keySize + valueSize + itemHeaderLen 317 offset, err := a.tbl.alloc(sz) 318 if err != nil { 319 return 0, err 320 } 321 322 a.itemsOffset = append(a.itemsOffset, offset) 323 itemBuf := a.tbl.getBytes(offset, sz) 324 binary.BigEndian.PutUint16(itemBuf[0:itemHeaderLen], uint16(keySize)) 325 copy(itemBuf[itemHeaderLen:itemHeaderLen+keySize], key) 326 copy(itemBuf[itemHeaderLen+keySize:sz], value) 327 328 a.num++ 329 330 if a.useMapIndex { 331 a.mapIndex.Add(hash.Crc32(key), uint32(a.num)) 332 } 333 334 return sz, nil 335 } 336 337 func (a *arrayTable) writeItemPrefixCompress(key, value []byte) (uint32, error) { 338 if a.prevKey == nil && a.prevValue == nil { 339 a.prevKey = make([]byte, 0, 1<<7) 340 a.prevKey = append(a.prevKey[:0], key...) 341 a.prevValue = value 342 a.prevHasShared = false 343 a.sharedKey = make([]byte, 0, 1<<6) 344 return 0, nil 345 } 346 347 shared := 0 348 n := len(key) 349 if n > len(a.prevKey) { 350 n = len(a.prevKey) 351 } 352 asUint64 := func(b []byte, i int) uint64 { 353 return binary.LittleEndian.Uint64(b[i:]) 354 } 355 356 for shared < n-7 && asUint64(key, shared) == asUint64(a.prevKey, shared) { 357 shared += 8 358 } 359 for shared < n && key[shared] == a.prevKey[shared] { 360 shared++ 361 } 362 363 if shared > 0 { 364 sharedKeyLength := len(a.sharedKey) 365 if shared < itemSharedMinLength || shared < sharedKeyLength { 366 shared = 0 367 } else { 368 if !a.prevHasShared { 369 a.sharedKey = append(a.sharedKey[:0], key[:shared]...) 370 a.sharedNum = a.num 371 } else if shared > sharedKeyLength+4 || a.num-a.sharedNum >= itemSharedRestart { 372 shared = 0 373 } else { 374 shared = sharedKeyLength 375 } 376 } 377 } 378 379 sz, err := a.writeSharedInternal(shared) 380 if err != nil { 381 return 0, err 382 } 383 384 a.prevKey = append(a.prevKey[:0], key...) 385 a.prevValue = value 386 if shared >= itemSharedMinLength { 387 a.prevHasShared = true 388 } else { 389 a.prevHasShared = false 390 a.sharedKey = a.sharedKey[:0] 391 a.sharedNum = 0 392 } 393 394 return sz, err 395 } 396 397 func (a *arrayTable) writeItemBlockCompress(key, value []byte) (uint32, error) { 398 if a.block == nil { 399 a.block = newPageBlock(a.header.version, a.blockSize) 400 } 401 402 a.block.writeItem(key, value) 403 404 if a.block.inuseBytes() >= a.blockSize && 405 a.block.itemCount() >= consts.BitpageBlockMinItemCount { 406 a.block.writeFinish() 407 408 blockBuf := compressEncode(a.compressedBuf, a.block.bytes()) 409 if cap(blockBuf) > cap(a.compressedBuf) { 410 a.compressedBuf = blockBuf[:cap(blockBuf)] 411 } 412 bufSize := len(blockBuf) 413 414 keySize := len(key) 415 sz := uint32(keySize + bufSize + itemHeaderLen) 416 offset, err := a.tbl.alloc(sz) 417 if err != nil { 418 return 0, err 419 } 420 421 a.itemsOffset = append(a.itemsOffset, offset) 422 itemBuf := a.tbl.getBytes(offset, sz) 423 binary.BigEndian.PutUint16(itemBuf[0:itemHeaderLen], uint16(keySize)) 424 copy(itemBuf[itemHeaderLen:itemHeaderLen+keySize], key) 425 copy(itemBuf[itemHeaderLen+keySize:sz], blockBuf) 426 427 a.block.reset(a.header.version) 428 a.num++ 429 430 return sz, nil 431 } 432 433 return 0, nil 434 } 435 436 func (a *arrayTable) writeItemBitrieCompress(key, value []byte) (uint32, error) { 437 a.bitrieIndex.Add(key, value) 438 439 a.num++ 440 441 return uint32(len(key) + len(value)), nil 442 } 443 444 func (a *arrayTable) writeFinish() error { 445 switch a.header.version { 446 case atVersionDefault, atVersionPrefixCompress: 447 return a.writeFinishNonBlockCompress() 448 case atVersionBlockCompress, atVersionPrefixBlockCompress: 449 return a.writeFinishBlockCompress() 450 case atVersionBitrieCompress: 451 return a.writeFinishBitrieCompress() 452 } 453 454 return a.writeFinishNonBlockCompress() 455 } 456 457 func (a *arrayTable) writeFinishNonBlockCompress() error { 458 if a.header.version == atVersionPrefixCompress && a.prevKey != nil && a.prevValue != nil { 459 if _, err := a.writeSharedInternal(0); err != nil { 460 return err 461 } 462 } 463 464 intSize := a.getIntIndexSize() 465 intIndexOffset, err := a.tbl.alloc(intSize) 466 if err != nil { 467 return err 468 } 469 intIndexBuf := a.tbl.getBytes(intIndexOffset, intSize) 470 intIndexPos := 0 471 for i := range a.itemsOffset { 472 binary.BigEndian.PutUint32(intIndexBuf[intIndexPos:intIndexPos+itemOffsetSize], a.itemsOffset[i]) 473 intIndexPos += itemOffsetSize 474 } 475 476 var mapIndexOffset uint32 477 if a.useMapIndex { 478 mapSize := a.mapIndex.Size() 479 mapIndexOffset, err = a.tbl.alloc(mapSize) 480 if err != nil { 481 return err 482 } 483 a.mapIndex.SetWriter(a.tbl.getBytes(mapIndexOffset, mapSize)) 484 if !a.mapIndex.Serialize() { 485 return errors.New("hash_index write fail") 486 } 487 488 a.mapIndex.Finish() 489 } 490 491 a.size = a.tbl.Size() 492 a.itemsOffset = nil 493 a.header.num = uint32(a.num) 494 a.header.intIndexOffset = intIndexOffset 495 a.header.mapIndexOffset = mapIndexOffset 496 a.writeHeader() 497 498 if err = a.tbl.mmapReadTruncate(int(a.size)); err != nil { 499 return err 500 } 501 502 a.dataIntBuffer() 503 504 a.block = nil 505 a.compressedBuf = nil 506 a.prevKey = nil 507 a.prevValue = nil 508 a.sharedKey = nil 509 510 return nil 511 } 512 513 func (a *arrayTable) writeFinishBlockCompress() error { 514 if !a.block.empty() { 515 a.block.writeFinish() 516 517 blockBuf := compressEncode(a.compressedBuf, a.block.bytes()) 518 bufSize := len(blockBuf) 519 520 key := consts.BdbMaxKey 521 keySize := len(consts.BdbMaxKey) 522 sz := uint32(keySize + bufSize + itemHeaderLen) 523 offset, err := a.tbl.alloc(sz) 524 if err != nil { 525 return err 526 } 527 528 a.itemsOffset = append(a.itemsOffset, offset) 529 itemBuf := a.tbl.getBytes(offset, sz) 530 binary.BigEndian.PutUint16(itemBuf[0:itemHeaderLen], uint16(keySize)) 531 copy(itemBuf[itemHeaderLen:itemHeaderLen+keySize], key) 532 copy(itemBuf[itemHeaderLen+keySize:sz], blockBuf) 533 534 a.block.reset(a.header.version) 535 536 a.num++ 537 } 538 539 intSize := a.getIntIndexSize() 540 intIndexOffset, err := a.tbl.alloc(intSize) 541 if err != nil { 542 return err 543 } 544 intIndexBuf := a.tbl.getBytes(intIndexOffset, intSize) 545 intIndexPos := 0 546 for i := range a.itemsOffset { 547 binary.BigEndian.PutUint32(intIndexBuf[intIndexPos:intIndexPos+itemOffsetSize], a.itemsOffset[i]) 548 intIndexPos += itemOffsetSize 549 } 550 551 a.size = a.tbl.Size() 552 a.itemsOffset = nil 553 a.header.num = uint32(a.num) 554 a.header.intIndexOffset = intIndexOffset 555 a.header.mapIndexOffset = 0 556 a.writeHeader() 557 558 if err = a.tbl.mmapReadTruncate(int(a.size)); err != nil { 559 return err 560 } 561 562 a.dataIntBuffer() 563 564 a.block = nil 565 a.compressedBuf = nil 566 a.prevKey = nil 567 a.prevValue = nil 568 a.sharedKey = nil 569 570 return nil 571 } 572 573 func (a *arrayTable) writeFinishBitrieCompress() error { 574 tblalloc := func(size uint32) uint32 { 575 offset, _ := a.tbl.alloc(size) 576 return offset 577 } 578 579 tblbytes := func(offset uint32, size uint32) []byte { 580 return a.tbl.getBytes(offset, size) 581 } 582 583 tblsize := func() uint32 { 584 return a.tbl.Size() 585 } 586 587 if !a.bitrieIndex.Serialize(tblalloc, tblbytes, tblsize) { 588 return errors.New("bitrie serialize fail") 589 } 590 a.bitrieIndex.Finish() 591 592 a.size = a.tbl.Size() 593 a.itemsOffset = nil 594 a.header.num = uint32(a.num) 595 a.header.intIndexOffset = 0 596 a.header.mapIndexOffset = 0 597 a.writeHeader() 598 599 if err := a.tbl.mmapReadTruncate(int(a.size)); err != nil { 600 return err 601 } 602 603 a.dataIntBuffer() 604 605 a.block = nil 606 a.compressedBuf = nil 607 a.prevKey = nil 608 a.prevValue = nil 609 a.sharedKey = nil 610 611 return nil 612 } 613 614 func (a *arrayTable) getSharedKey(i int, key []byte, sharedCache *sharedInfo) ([]byte, []byte) { 615 offset := key[0] 616 switch offset { 617 case itemSharedMin: 618 return key[3:], nil 619 case itemSharedMax: 620 return key[1:], nil 621 default: 622 idx := i - int(offset) 623 624 if sharedCache != nil && sharedCache.idx == idx && len(sharedCache.key) >= itemSharedMinLength { 625 return sharedCache.key, key[1:] 626 } 627 628 itemOffset := a.getItemOffset(idx) 629 if itemOffset == 0 { 630 return nil, nil 631 } 632 633 sharedKeySize := uint32(binary.BigEndian.Uint16(a.tbl.getBytes(itemOffset, itemHeaderLen))) 634 sharedKey := a.tbl.getBytes(itemOffset+itemHeaderLen, sharedKeySize) 635 636 sharedKeyOffset := sharedKey[0] 637 if sharedKeyOffset != itemSharedMin { 638 return nil, nil 639 } 640 641 sharedKeyLenght := uint32(binary.BigEndian.Uint16(sharedKey[1:]) + 3) 642 if sharedKeyLenght > sharedKeySize { 643 return nil, nil 644 } 645 646 if sharedCache != nil && sharedCache.idx != idx { 647 sharedCache.idx = idx 648 sharedCache.key = sharedKey[3:sharedKeyLenght] 649 } 650 651 return sharedKey[3:sharedKeyLenght], key[1:] 652 } 653 } 654 655 func (a *arrayTable) checkPositon(i int) bool { 656 return i >= 0 && i < a.num 657 } 658 659 func (a *arrayTable) getItemOffset(i int) uint32 { 660 if i < 0 || i >= a.num { 661 return 0 662 } 663 664 pos := i * itemOffsetSize 665 itemOffset := binary.BigEndian.Uint32(a.intIndex[pos : pos+itemOffsetSize]) 666 667 return itemOffset 668 } 669 670 func (a *arrayTable) getKey(i int) ([]byte, []byte) { 671 itemOffset := a.getItemOffset(i) 672 if itemOffset == 0 { 673 return nil, nil 674 } 675 676 keySize := uint32(binary.BigEndian.Uint16(a.tbl.getBytes(itemOffset, itemHeaderLen))) 677 key := a.tbl.getBytes(itemOffset+itemHeaderLen, keySize) 678 679 if a.header.version == atVersionPrefixCompress { 680 return a.getSharedKey(i, key, nil) 681 } 682 683 return key, nil 684 } 685 686 func (a *arrayTable) getMaxKey() []byte { 687 pos := a.num - 1 688 itemOffset := a.getItemOffset(pos) 689 if itemOffset == 0 { 690 return nil 691 } 692 693 keySize := uint32(binary.BigEndian.Uint16(a.tbl.getBytes(itemOffset, itemHeaderLen))) 694 key := a.tbl.getBytes(itemOffset+itemHeaderLen, keySize) 695 696 if a.header.version == atVersionPrefixCompress { 697 sharedKey1, sharedKey2 := a.getSharedKey(pos, key, nil) 698 sk1l := len(sharedKey1) 699 sk2l := len(sharedKey2) 700 rawKey := make([]byte, sk1l+sk2l) 701 copy(rawKey[:sk1l], sharedKey1) 702 copy(rawKey[sk1l:], sharedKey2) 703 704 return rawKey 705 } 706 707 return key 708 } 709 710 func (a *arrayTable) getKV(i int) ([]byte, []byte) { 711 itemOffset := a.getItemOffset(i) 712 if itemOffset == 0 { 713 return nil, nil 714 } 715 716 var itemSize uint32 717 if i == a.num-1 { 718 itemSize = a.header.intIndexOffset - itemOffset 719 } else { 720 itemSize = a.getItemOffset(i+1) - itemOffset 721 } 722 723 keySize := uint32(binary.BigEndian.Uint16(a.tbl.getBytes(itemOffset, itemHeaderLen))) 724 keyOffset := itemOffset + itemHeaderLen 725 key := a.tbl.getBytes(keyOffset, keySize) 726 valueSize := itemSize - keySize - itemHeaderLen 727 value := a.tbl.getBytes(keyOffset+keySize, valueSize) 728 729 return key, value 730 } 731 732 func (a *arrayTable) getSharedKV(i int, sharedCache *sharedInfo) ([]byte, []byte, []byte) { 733 key, value := a.getKV(i) 734 if key == nil { 735 return nil, nil, nil 736 } 737 738 if a.header.version == atVersionPrefixCompress { 739 sharedKey1, sharedKey2 := a.getSharedKey(i, key, sharedCache) 740 return sharedKey1, sharedKey2, value 741 } 742 743 return key, nil, value 744 745 } 746 747 func (a *arrayTable) get(key []byte, khash uint32) ([]byte, bool, internalKeyKind, func()) { 748 if a.header.version == atVersionBitrieCompress { 749 value, exist := a.bitrieIndex.Get(key) 750 if exist { 751 return value, true, internalKeyKindSet, nil 752 } else { 753 return nil, false, internalKeyKindInvalid, nil 754 } 755 } 756 757 var pos int 758 if a.useMapIndex { 759 pos = a.findKeyByMapIndex(khash) 760 sharedKey1, sharedKey2 := a.getKey(pos) 761 if sharedKey1 == nil { 762 return nil, false, internalKeyKindInvalid, nil 763 } 764 if atEqual(sharedKey1, sharedKey2, key) { 765 _, value := a.getKV(pos) 766 return value, true, internalKeyKindSet, nil 767 } 768 } 769 770 pos = a.findKeyByIntIndex(key) 771 772 if a.isNonBlock() { 773 sharedKey1, sharedKey2, value := a.getSharedKV(pos, nil) 774 if sharedKey1 == nil || !atEqual(sharedKey1, sharedKey2, key) { 775 return nil, false, internalKeyKindInvalid, nil 776 } 777 778 return value, true, internalKeyKindSet, nil 779 } 780 781 blockBuf, closer, blockExist := a.blockCache.GetBlock(a.cacheID, uint64(pos)) 782 if !blockExist { 783 _, blockBuf = a.getKV(pos) 784 if len(blockBuf) == 0 { 785 return nil, false, internalKeyKindInvalid, nil 786 } 787 788 var compressedBuf []byte 789 compressedBuf, closer = bytepools.ReaderBytePools.GetMaxBytePool() 790 blockBuf, _ = compressDecode(compressedBuf, blockBuf) 791 _ = a.blockCache.SetBlock(a.cacheID, uint64(pos), blockBuf) 792 } 793 794 pb := pageBlock{} 795 openPageBlock(&pb, blockBuf) 796 value, exist, kind := pb.get(key) 797 if !exist && closer != nil { 798 closer() 799 closer = nil 800 } 801 802 return value, exist, kind, closer 803 } 804 805 func (a *arrayTable) isNonBlock() bool { 806 return a.header.version == atVersionDefault || 807 a.header.version == atVersionPrefixCompress 808 } 809 810 func (a *arrayTable) newIter(opts *iterOptions) internalIterator { 811 iter := atIterPool.Get().(*arrayTableIterator) 812 iter.at = a 813 814 if opts != nil { 815 iter.disableCache = opts.DisableCache 816 } else { 817 iter.disableCache = false 818 } 819 820 if a.header.version == atVersionPrefixCompress { 821 if cap(iter.keyBuf) == 0 { 822 iter.keyBuf = make([]byte, 0, 1<<7) 823 } 824 if iter.sharedCache == nil { 825 iter.sharedCache = &sharedInfo{idx: -1, key: nil} 826 } 827 } 828 829 return iter 830 } 831 832 func (a *arrayTable) delPercent() float64 { 833 return 0.0 834 } 835 836 func (a *arrayTable) itemCount() int { 837 return a.num 838 } 839 840 func (a *arrayTable) inuseBytes() uint64 { 841 return uint64(a.tbl.Size()) 842 } 843 844 func (a *arrayTable) dataBytes() uint64 { 845 return uint64(a.header.intIndexOffset - a.header.dataOffset) 846 } 847 848 func (a *arrayTable) close() error { 849 if a.tbl == nil { 850 return nil 851 } 852 853 if err := a.tbl.close(); err != nil { 854 return err 855 } 856 857 a.tbl = nil 858 return nil 859 } 860 861 func (a *arrayTable) readyForFlush() bool { 862 return true 863 } 864 865 func (a *arrayTable) path() string { 866 if a.tbl == nil { 867 return "" 868 } 869 return a.tbl.path 870 } 871 872 func (a *arrayTable) idxFilePath() string { 873 return "" 874 } 875 876 func (a *arrayTable) empty() bool { 877 return a.num == 0 878 } 879 880 func (a *arrayTable) findKeyByMapIndex(khash uint32) int { 881 var pos int 882 v, exist := a.mapIndex.Get32(khash) 883 if exist { 884 pos = int(v - 1) 885 } else { 886 pos = a.num 887 } 888 return pos 889 } 890 891 func (a *arrayTable) findKeyByIntIndex(key []byte) int { 892 return sort.Search(a.num, func(i int) bool { 893 sharedKey1, sharedKey2 := a.getKey(i) 894 return atCompare(sharedKey1, sharedKey2, key) != -1 895 }) 896 } 897 898 func atCompare(sharedKey1 []byte, sharedKey2 []byte, key []byte) int { 899 if sharedKey1 != nil && sharedKey2 == nil { 900 return bytes.Compare(sharedKey1, key) 901 } else { 902 sk1l := len(sharedKey1) 903 kl := len(key) 904 if sk1l <= kl { 905 if r := bytes.Compare(sharedKey1, key[:sk1l]); r != 0 { 906 return r 907 } else { 908 return bytes.Compare(sharedKey2, key[sk1l:]) 909 } 910 } else { 911 return bytes.Compare(sharedKey1, key) 912 } 913 } 914 } 915 916 func atEqual(sharedKey1 []byte, sharedKey2 []byte, key []byte) bool { 917 if sharedKey1 != nil && sharedKey2 == nil { 918 return bytes.Equal(sharedKey1, key) 919 } else { 920 sk1l := len(sharedKey1) 921 sk2l := len(sharedKey2) 922 kl := len(key) 923 if sk1l+sk2l == kl && bytes.Equal(sharedKey1, key[:sk1l]) && bytes.Equal(sharedKey2, key[sk1l:]) { 924 return true 925 } 926 } 927 928 return false 929 } 930 931 func compressEncode(dst, src []byte) []byte { 932 return snappy.Encode(dst, src) 933 } 934 935 func compressDecode(dst, src []byte) ([]byte, error) { 936 return snappy.Decode(dst, src) 937 }