| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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. |
| */ |
| |
| #include "paimon/common/sst/block_iterator.h" |
| |
| #include "paimon/common/sst/block_reader.h" |
| |
| namespace paimon { |
| BlockIterator::BlockIterator(const std::shared_ptr<BlockReader>& reader) |
| : input_(reader->BlockInput()), reader_(reader) {} |
| |
| bool BlockIterator::HasNext() const { |
| return polled_position_ >= 0 || input_.IsReadable(); |
| } |
| |
| Result<BlockEntry> BlockIterator::Next() { |
| if (!HasNext()) { |
| return Status::Invalid("no such element"); |
| } |
| if (polled_position_ >= 0) { |
| PAIMON_RETURN_NOT_OK(input_.SetPosition(polled_position_)); |
| polled_position_ = -1; |
| return ReadEntry(); |
| } |
| return ReadEntry(); |
| } |
| |
| Result<BlockEntry> BlockIterator::ReadEntry() { |
| PAIMON_ASSIGN_OR_RAISE(int32_t key_length, input_.ReadVarLenInt()); |
| auto key = input_.ReadSliceView(key_length); |
| PAIMON_ASSIGN_OR_RAISE(int32_t value_length, input_.ReadVarLenInt()); |
| auto value = input_.ReadSliceView(value_length); |
| return BlockEntry(key, value); |
| } |
| |
| Result<MemorySlice> BlockIterator::SkipKeyAndReadValue() { |
| if (polled_position_ >= 0) { |
| PAIMON_RETURN_NOT_OK(input_.SetPosition(polled_position_)); |
| polled_position_ = -1; |
| } |
| PAIMON_ASSIGN_OR_RAISE(int32_t key_length, input_.ReadVarLenInt()); |
| PAIMON_RETURN_NOT_OK(input_.SetPosition(input_.Position() + key_length)); |
| PAIMON_ASSIGN_OR_RAISE(int32_t value_length, input_.ReadVarLenInt()); |
| return input_.ReadSliceView(value_length); |
| } |
| |
| Result<MemorySlice> BlockIterator::ReadKeyAndSkipValue() { |
| PAIMON_ASSIGN_OR_RAISE(int32_t key_length, input_.ReadVarLenInt()); |
| auto key = input_.ReadSliceView(key_length); |
| PAIMON_ASSIGN_OR_RAISE(int32_t value_length, input_.ReadVarLenInt()); |
| PAIMON_RETURN_NOT_OK(input_.SetPosition(input_.Position() + value_length)); |
| return key; |
| } |
| |
| Result<bool> BlockIterator::SeekTo(const MemorySlice& target_key) { |
| int32_t left = 0; |
| int32_t right = reader_->RecordCount() - 1; |
| polled_position_ = -1; |
| |
| while (left <= right) { |
| int32_t mid = left + (right - left) / 2; |
| |
| int32_t entry_position = reader_->SeekTo(mid); |
| PAIMON_RETURN_NOT_OK(input_.SetPosition(entry_position)); |
| |
| PAIMON_ASSIGN_OR_RAISE(MemorySlice mid_key, ReadKeyAndSkipValue()); |
| PAIMON_ASSIGN_OR_RAISE(int32_t compare, reader_->Comparator()(mid_key, target_key)); |
| |
| if (compare == 0) { |
| polled_position_ = entry_position; |
| return true; |
| } else if (compare > 0) { |
| // mid_key > target_key, this could be the first key >= target_key |
| polled_position_ = entry_position; |
| right = mid - 1; |
| } else { |
| // mid_key < target_key, need to look at larger keys |
| // Don't reset polled_position_ here - keep the last position where key > target |
| left = mid + 1; |
| } |
| } |
| |
| // If we exit the loop without finding exact match, polled_position_ points to |
| // the first entry with key >= target_key (if any), or -1 if all keys < target_key |
| return false; |
| } |
| |
| } // namespace paimon |