TODO: use redwood prefix trick to optimize cpu comparison
| 771 | |
| 772 | // TODO: use redwood prefix trick to optimize cpu comparison |
| 773 | static Standalone<VectorRef<ParsedDeltaBoundaryRef>> loadSnapshotFile( |
| 774 | const Standalone<StringRef>& fileName, |
| 775 | const StringRef& snapshotData, |
| 776 | const KeyRangeRef& keyRange, |
| 777 | Optional<BlobGranuleCipherKeysCtx> cipherKeysCtx) { |
| 778 | Standalone<VectorRef<ParsedDeltaBoundaryRef>> results; |
| 779 | |
| 780 | if (BG_ENCRYPT_COMPRESS_DEBUG) { |
| 781 | TraceEvent(SevDebug, "LoadChunkedSnapshot") |
| 782 | .detail("FileName", fileName.toString()) |
| 783 | .detail("RangeBegin", keyRange.begin.printable()) |
| 784 | .detail("RangeEnd", keyRange.end.printable()) |
| 785 | .detail("Encrypted", cipherKeysCtx.present()); |
| 786 | } |
| 787 | |
| 788 | Standalone<IndexedBlobGranuleFile> file = IndexedBlobGranuleFile::fromFileBytes(snapshotData, cipherKeysCtx); |
| 789 | |
| 790 | ASSERT(file.fileType == SNAPSHOT_FILE_TYPE); |
| 791 | ASSERT(file.chunkStartOffset > 0); |
| 792 | |
| 793 | // empty snapshot file |
| 794 | if (file.indexBlockRef.block.children.empty()) { |
| 795 | return results; |
| 796 | } |
| 797 | |
| 798 | ASSERT(file.indexBlockRef.block.children.size() >= 2); |
| 799 | |
| 800 | // find range of blocks needed to read |
| 801 | ChildBlockPointerRef* currentBlock = file.findStartBlock(keyRange.begin); |
| 802 | |
| 803 | if (currentBlock == (file.indexBlockRef.block.children.end() - 1) || keyRange.end <= currentBlock->key) { |
| 804 | return results; |
| 805 | } |
| 806 | |
| 807 | bool lastBlock = false; |
| 808 | |
| 809 | // FIXME: shared prefix for key comparison |
| 810 | while (!lastBlock) { |
| 811 | auto nextBlock = currentBlock; |
| 812 | nextBlock++; |
| 813 | lastBlock = (nextBlock == (file.indexBlockRef.block.children.end() - 1)) || (keyRange.end <= nextBlock->key); |
| 814 | Standalone<GranuleSnapshot> dataBlock = |
| 815 | file.getChild<GranuleSnapshot>(currentBlock, cipherKeysCtx, file.chunkStartOffset); |
| 816 | ASSERT(!dataBlock.empty()); |
| 817 | ASSERT(currentBlock->key == dataBlock.front().key); |
| 818 | |
| 819 | bool anyRows = false; |
| 820 | for (auto& entry : dataBlock) { |
| 821 | if (!results.empty() && !lastBlock) { |
| 822 | // no key comparisons needed |
| 823 | results.emplace_back(results.arena(), entry); |
| 824 | anyRows = true; |
| 825 | } else if ((!results.empty() || entry.key >= keyRange.begin) && (!lastBlock || entry.key < keyRange.end)) { |
| 826 | results.emplace_back(results.arena(), entry); |
| 827 | anyRows = true; |
| 828 | } else if (!results.empty() && lastBlock) { |
| 829 | break; |
| 830 | } |
no test coverage detected