[VFS/STFS] Cache any hash-blocks we read from in memory

This commit is contained in:
emoose 2021-04-19 02:18:05 +01:00 committed by Rick Gibbed
parent 6ba9b032a3
commit 99b7848a34
2 changed files with 60 additions and 39 deletions

View File

@ -624,55 +624,67 @@ size_t StfsContainerDevice::BlockToHashBlockOffsetSTFS(
const StfsHashEntry* StfsContainerDevice::GetBlockHash(const uint8_t* map_ptr, const StfsHashEntry* StfsContainerDevice::GetBlockHash(const uint8_t* map_ptr,
uint32_t block_index) { uint32_t block_index) {
auto& volume_descriptor = header_.metadata.stfs_volume_descriptor;
// Offset for selecting the secondary hash block, in packages that have them // Offset for selecting the secondary hash block, in packages that have them
uint32_t secondary_table_offset = uint32_t secondary_table_offset =
header_.metadata.stfs_volume_descriptor.flags.root_active_index volume_descriptor.flags.root_active_index ? kSectorSize : 0;
? kSectorSize
: 0;
auto hash_offset_lv0 = BlockToHashBlockOffsetSTFS(block_index, 0);
if (!cached_hash_tables_.count(hash_offset_lv0)) {
// If this is read_only_format then it doesn't contain secondary blocks, no // If this is read_only_format then it doesn't contain secondary blocks, no
// need to check upper hash levels // need to check upper hash levels
if (header_.metadata.stfs_volume_descriptor.flags.read_only_format) { if (volume_descriptor.flags.read_only_format) {
secondary_table_offset = 0; secondary_table_offset = 0;
} else { } else {
// Not a read-only package, need to check each levels active index flag to // Not a read-only package, need to check each levels active index flag to
// see if we need to use secondary block or not // see if we need to use secondary block or not
// Check L2 active index flag... // Check level1 table if package has it
if (header_.metadata.stfs_volume_descriptor.allocated_block_count > if (volume_descriptor.allocated_block_count > kBlocksPerHashLevel[0]) {
auto hash_offset_lv1 = BlockToHashBlockOffsetSTFS(block_index, 1);
if (!cached_hash_tables_.count(hash_offset_lv1)) {
// Check level2 table if package has it
if (volume_descriptor.allocated_block_count >
kBlocksPerHashLevel[1]) { kBlocksPerHashLevel[1]) {
auto hash_offset = BlockToHashBlockOffsetSTFS(block_index, 2); auto hash_offset_lv2 = BlockToHashBlockOffsetSTFS(block_index, 2);
auto hash_table = map_ptr + hash_offset + secondary_table_offset;
if (!cached_hash_tables_.count(hash_offset_lv2)) {
cached_hash_tables_[hash_offset_lv2] =
*reinterpret_cast<const StfsHashTable*>(
map_ptr + hash_offset_lv2 + secondary_table_offset);
}
auto record = auto record =
(block_index / kBlocksPerHashLevel[1]) % kBlocksPerHashLevel[0]; (block_index / kBlocksPerHashLevel[1]) % kBlocksPerHashLevel[0];
auto record_data = auto record_data =
reinterpret_cast<const StfsHashEntry*>(hash_table + record * 0x18); &cached_hash_tables_[hash_offset_lv2].entries[record];
secondary_table_offset = secondary_table_offset =
record_data->levelN_activeindex() ? kSectorSize : 0; record_data->levelN_activeindex() ? kSectorSize : 0;
} }
// Check L1 active index flag... cached_hash_tables_[hash_offset_lv1] =
if (header_.metadata.stfs_volume_descriptor.allocated_block_count > *reinterpret_cast<const StfsHashTable*>(
kBlocksPerHashLevel[0]) { map_ptr + hash_offset_lv1 + secondary_table_offset);
auto hash_offset = BlockToHashBlockOffsetSTFS(block_index, 1); }
auto hash_table = map_ptr + hash_offset + secondary_table_offset;
auto record = auto record =
(block_index / kBlocksPerHashLevel[0]) % kBlocksPerHashLevel[0]; (block_index / kBlocksPerHashLevel[0]) % kBlocksPerHashLevel[0];
auto record_data = auto record_data =
reinterpret_cast<const StfsHashEntry*>(hash_table + record * 0x18); &cached_hash_tables_[hash_offset_lv1].entries[record];
secondary_table_offset = secondary_table_offset =
record_data->levelN_activeindex() ? kSectorSize : 0; record_data->levelN_activeindex() ? kSectorSize : 0;
} }
} }
auto hash_offset = BlockToHashBlockOffsetSTFS(block_index, 0); cached_hash_tables_[hash_offset_lv0] =
auto hash_table = map_ptr + hash_offset + secondary_table_offset; *reinterpret_cast<const StfsHashTable*>(map_ptr + hash_offset_lv0 +
secondary_table_offset);
}
auto record = block_index % kBlocksPerHashLevel[0]; auto record = block_index % kBlocksPerHashLevel[0];
auto record_data = auto record_data = &cached_hash_tables_[hash_offset_lv0].entries[record];
reinterpret_cast<const StfsHashEntry*>(hash_table + record * 0x18);
return record_data; return record_data;
} }

View File

@ -135,6 +135,13 @@ struct StfsHashEntry {
}; };
static_assert_size(StfsHashEntry, 0x18); static_assert_size(StfsHashEntry, 0x18);
struct StfsHashTable {
StfsHashEntry entries[170];
xe::be<uint32_t> num_blocks; // num L0 blocks covered by this table?
uint8_t padding[12];
};
static_assert_size(StfsHashTable, 0x1000);
/* SVOD structures */ /* SVOD structures */
struct SvodDeviceDescriptor { struct SvodDeviceDescriptor {
uint8_t descriptor_length; uint8_t descriptor_length;
@ -483,6 +490,8 @@ class StfsContainerDevice : public Device {
SvodLayoutType svod_layout_; SvodLayoutType svod_layout_;
uint32_t blocks_per_hash_table_; uint32_t blocks_per_hash_table_;
uint32_t block_step[2]; uint32_t block_step[2];
std::unordered_map<size_t, StfsHashTable> cached_hash_tables_;
}; };
} // namespace vfs } // namespace vfs