This function will not (and cannot) check if index changed in between this function call. It's caller's responsibility to make sure the index is not changed and no race condition happens. Currently, this will be called under the lock for the proper mutex for the index, so it's fine.
| 958 | // Currently, this will be called under the lock for the proper mutex for the |
| 959 | // index, so it's fine. |
| 960 | Status BlockCache::onReadCombinedEntryBlock(uint32_t address, |
| 961 | uint32_t readSize, |
| 962 | Buffer& cebBuffer) { |
| 963 | auto addrEnd = decodeRelAddress(address); |
| 964 | // It won't care about seq number here (giving it as std::nullopt). It's |
| 965 | // caller's responsibility to check about the race condition for the index |
| 966 | // change. |
| 967 | auto desc = regionManager_.openForRead(addrEnd.rid(), std::nullopt); |
| 968 | if (desc.status() != OpenStatus::Ready) { |
| 969 | // In rare cases, Region can return 'Retry' when it's being released after |
| 970 | // the reclaim. Checking the index again will resolve it since index should |
| 971 | // have been updated with the new location |
| 972 | return Status::Retry; |
| 973 | } |
| 974 | |
| 975 | // For Combined entry block, we don't have a key following the header. Every |
| 976 | // key info will be within the value itself |
| 977 | uint32_t size = serializedSize(0, readSize); |
| 978 | |
| 979 | auto buffer = regionManager_.read(desc, addrEnd.sub((uint32_t)size), size); |
| 980 | regionManager_.close(std::move(desc)); |
| 981 | |
| 982 | if (buffer.isNull()) { |
| 983 | return Status::DeviceError; |
| 984 | } |
| 985 | |
| 986 | auto entryEnd = buffer.data() + buffer.size(); |
| 987 | auto entryDesc = *reinterpret_cast<EntryDesc*>(entryEnd - sizeof(EntryDesc)); |
| 988 | // Check header checksum |
| 989 | if (entryDesc.csSelf != entryDesc.computeChecksum()) { |
| 990 | XLOGF(ERR, |
| 991 | "Item header checksum mismatch in onReadCombinedEntryBlock(). " |
| 992 | "Region {} is " |
| 993 | "likely corrupted. Expected: {}, Actual: {}, Offset-end: {}, " |
| 994 | "Physical-offset-end: {}, Header size: {}, Header (hex): {}", |
| 995 | addrEnd.rid().index(), entryDesc.csSelf, entryDesc.computeChecksum(), |
| 996 | addrEnd.offset(), regionManager_.physicalOffset(addrEnd), |
| 997 | sizeof(EntryDesc), |
| 998 | folly::hexlify( |
| 999 | folly::ByteRange(entryEnd - sizeof(EntryDesc), entryEnd))); |
| 1000 | return Status::ChecksumError; |
| 1001 | } |
| 1002 | |
| 1003 | // Check if EntryDesc matches with the Combined entry block |
| 1004 | if (entryDesc.keyHash != kCombinedEntrySignatureValue || |
| 1005 | entryDesc.keySize != 0 || entryDesc.valueSize != readSize) { |
| 1006 | // EntryDesc doesn't seem to be correct for Combined entry block. Something |
| 1007 | // is wrong and we should return error. |
| 1008 | XLOGF(ERR, |
| 1009 | "Item header doesn't seem to be correct for Combined entry block in " |
| 1010 | "onReadCombinedEntryBlock(). " |
| 1011 | "Region {} is " |
| 1012 | "likely corrupted. keyHash: {}, keySize: {}, valueSize: {}, " |
| 1013 | "Offset-end: {}, " |
| 1014 | "Physical-offset-end: {}, Header size: {}, Header (hex): {}", |
| 1015 | addrEnd.rid().index(), entryDesc.keyHash, entryDesc.keySize, |
| 1016 | entryDesc.valueSize, addrEnd.offset(), |
| 1017 | regionManager_.physicalOffset(addrEnd), sizeof(EntryDesc), |
nothing calls this directly
no test coverage detected