|
| 1 | +//===----------------------------------------------------------------------===// |
| 2 | +// |
| 3 | +// BusTub |
| 4 | +// |
| 5 | +// extendible_htable_directory_page.h |
| 6 | +// |
| 7 | +// Identification: src/include/storage/page/extendible_htable_directory_page.h |
| 8 | +// |
| 9 | +// Copyright (c) 2015-2023, Carnegie Mellon University Database Group |
| 10 | +// |
| 11 | +//===----------------------------------------------------------------------===// |
| 12 | + |
| 13 | +/** |
| 14 | + * Directory page format: |
| 15 | + * -------------------------------------------------------------------------------------- |
| 16 | + * | MaxSize (4) | GlobalDepth (4) | LocalDepths (512) | BucketPageIds(2048) | Free(1528) |
| 17 | + * -------------------------------------------------------------------------------------- |
| 18 | + */ |
| 19 | + |
| 20 | +#pragma once |
| 21 | + |
| 22 | +#include <cassert> |
| 23 | +#include <climits> |
| 24 | +#include <cstdlib> |
| 25 | +#include <string> |
| 26 | + |
| 27 | +#include "common/config.h" |
| 28 | +#include "storage/index/generic_key.h" |
| 29 | +#include "storage/page/hash_table_page_defs.h" |
| 30 | + |
| 31 | +namespace bustub { |
| 32 | + |
| 33 | +static constexpr uint64_t HTABLE_DIRECTORY_PAGE_METADATA_SIZE = sizeof(uint32_t) * 2; |
| 34 | + |
| 35 | +/** |
| 36 | + * HTABLE_DIRECTORY_ARRAY_SIZE is the number of page_ids that can fit in the directory page of an extendible hash index. |
| 37 | + * This is 512 because the directory array must grow in powers of 2, and 1024 page_ids leaves zero room for |
| 38 | + * storage of the other member variables: page_id_, lsn_, global_depth_, and the array local_depths_. |
| 39 | + * Extending the directory implementation to span multiple pages would be a meaningful improvement to the |
| 40 | + * implementation. |
| 41 | + */ |
| 42 | +static constexpr uint64_t HTABLE_DIRECTORY_ARRAY_SIZE = 512; |
| 43 | + |
| 44 | +/** |
| 45 | + * Directory Page for extendible hash table. |
| 46 | + */ |
| 47 | +class ExtendibleHTableDirectoryPage { |
| 48 | + public: |
| 49 | + // Delete all constructor / destructor to ensure memory safety |
| 50 | + ExtendibleHTableDirectoryPage() = delete; |
| 51 | + DISALLOW_COPY_AND_MOVE(ExtendibleHTableDirectoryPage); |
| 52 | + |
| 53 | + /** |
| 54 | + * After creating a new directory page from buffer pool, must call initialize |
| 55 | + * method to set default values |
| 56 | + * @param max_size Max size of the array in the directory page |
| 57 | + */ |
| 58 | + void Init(int max_size = HTABLE_DIRECTORY_ARRAY_SIZE); |
| 59 | + |
| 60 | + /** |
| 61 | + * Get the bucket page id that the key is hashed to |
| 62 | + * |
| 63 | + * @param hash the hash of the key |
| 64 | + * @return bucket page_id current key is hashed to |
| 65 | + */ |
| 66 | + auto HashToBucketPageId(uint32_t hash) -> page_id_t; |
| 67 | + |
| 68 | + /** |
| 69 | + * Lookup a bucket page using a directory index |
| 70 | + * |
| 71 | + * @param bucket_idx the index in the directory to lookup |
| 72 | + * @return bucket page_id corresponding to bucket_idx |
| 73 | + */ |
| 74 | + auto GetBucketPageId(uint32_t bucket_idx) -> page_id_t; |
| 75 | + |
| 76 | + /** |
| 77 | + * Updates the directory index using a bucket index and page_id |
| 78 | + * |
| 79 | + * @param bucket_idx directory index at which to insert page_id |
| 80 | + * @param bucket_page_id page_id to insert |
| 81 | + */ |
| 82 | + void SetBucketPageId(uint32_t bucket_idx, page_id_t bucket_page_id); |
| 83 | + |
| 84 | + /** |
| 85 | + * Gets the split image of an index |
| 86 | + * |
| 87 | + * @param bucket_idx the directory index for which to find the split image |
| 88 | + * @return the directory index of the split image |
| 89 | + **/ |
| 90 | + auto GetSplitImageIndex(uint32_t bucket_idx) -> uint32_t; |
| 91 | + |
| 92 | + /** |
| 93 | + * GetGlobalDepthMask - returns a mask of global_depth 1's and the rest 0's. |
| 94 | + * |
| 95 | + * In Extendible Hashing we map a key to a directory index |
| 96 | + * using the following hash + mask function. |
| 97 | + * |
| 98 | + * DirectoryIndex = Hash(key) & GLOBAL_DEPTH_MASK |
| 99 | + * |
| 100 | + * where GLOBAL_DEPTH_MASK is a mask with exactly GLOBAL_DEPTH 1's from LSB |
| 101 | + * upwards. For example, global depth 3 corresponds to 0x00000007 in a 32-bit |
| 102 | + * representation. |
| 103 | + * |
| 104 | + * @return mask of global_depth 1's and the rest 0's (with 1's from LSB upwards) |
| 105 | + */ |
| 106 | + auto GetGlobalDepthMask() -> uint32_t; |
| 107 | + |
| 108 | + /** |
| 109 | + * GetLocalDepthMask - same as global depth mask, except it |
| 110 | + * uses the local depth of the bucket located at bucket_idx |
| 111 | + * |
| 112 | + * @param bucket_idx the index to use for looking up local depth |
| 113 | + * @return mask of local 1's and the rest 0's (with 1's from LSB upwards) |
| 114 | + */ |
| 115 | + auto GetLocalDepthMask(uint32_t bucket_idx) -> uint32_t; |
| 116 | + |
| 117 | + /** |
| 118 | + * Get the global depth of the hash table directory |
| 119 | + * |
| 120 | + * @return the global depth of the directory |
| 121 | + */ |
| 122 | + auto GetGlobalDepth() -> uint32_t; |
| 123 | + |
| 124 | + /** |
| 125 | + * Increment the global depth of the directory |
| 126 | + */ |
| 127 | + void IncrGlobalDepth(); |
| 128 | + |
| 129 | + /** |
| 130 | + * Decrement the global depth of the directory |
| 131 | + */ |
| 132 | + void DecrGlobalDepth(); |
| 133 | + |
| 134 | + /** |
| 135 | + * @return true if the directory can be shrunk |
| 136 | + */ |
| 137 | + auto CanShrink() -> bool; |
| 138 | + |
| 139 | + /** |
| 140 | + * @return the current directory size |
| 141 | + */ |
| 142 | + auto Size() -> uint32_t; |
| 143 | + |
| 144 | + /** |
| 145 | + * Gets the local depth of the bucket at bucket_idx |
| 146 | + * |
| 147 | + * @param bucket_idx the bucket index to lookup |
| 148 | + * @return the local depth of the bucket at bucket_idx |
| 149 | + */ |
| 150 | + auto GetLocalDepth(uint32_t bucket_idx) -> uint32_t; |
| 151 | + |
| 152 | + /** |
| 153 | + * Set the local depth of the bucket at bucket_idx to local_depth |
| 154 | + * |
| 155 | + * @param bucket_idx bucket index to update |
| 156 | + * @param local_depth new local depth |
| 157 | + */ |
| 158 | + void SetLocalDepth(uint32_t bucket_idx, uint8_t local_depth); |
| 159 | + |
| 160 | + /** |
| 161 | + * Increment the local depth of the bucket at bucket_idx |
| 162 | + * @param bucket_idx bucket index to increment |
| 163 | + */ |
| 164 | + void IncrLocalDepth(uint32_t bucket_idx); |
| 165 | + |
| 166 | + /** |
| 167 | + * Decrement the local depth of the bucket at bucket_idx |
| 168 | + * @param bucket_idx bucket index to decrement |
| 169 | + */ |
| 170 | + void DecrLocalDepth(uint32_t bucket_idx); |
| 171 | + |
| 172 | + /** |
| 173 | + * Gets the high bit corresponding to the bucket's local depth. |
| 174 | + * This is not the same as the bucket index itself. This method |
| 175 | + * is helpful for finding the pair, or "split image", of a bucket. |
| 176 | + * |
| 177 | + * @param bucket_idx bucket index to lookup |
| 178 | + * @return the high bit corresponding to the bucket's local depth |
| 179 | + */ |
| 180 | + auto GetLocalHighBit(uint32_t bucket_idx) -> uint32_t; |
| 181 | + |
| 182 | + /** |
| 183 | + * VerifyIntegrity |
| 184 | + * |
| 185 | + * Verify the following invariants: |
| 186 | + * (1) All LD <= GD. |
| 187 | + * (2) Each bucket has precisely 2^(GD - LD) pointers pointing to it. |
| 188 | + * (3) The LD is the same at each index with the same bucket_page_id |
| 189 | + */ |
| 190 | + void VerifyIntegrity(); |
| 191 | + |
| 192 | + /** |
| 193 | + * Prints the current directory |
| 194 | + */ |
| 195 | + void PrintDirectory(); |
| 196 | + |
| 197 | + private: |
| 198 | + uint32_t max_size_; |
| 199 | + uint32_t global_depth_; |
| 200 | + uint8_t local_depths_[HTABLE_DIRECTORY_ARRAY_SIZE]; |
| 201 | + page_id_t bucket_page_ids_[HTABLE_DIRECTORY_ARRAY_SIZE]; |
| 202 | +}; |
| 203 | + |
| 204 | +static_assert(sizeof(page_id_t) == 4); |
| 205 | + |
| 206 | +static_assert(sizeof(ExtendibleHTableDirectoryPage) == HTABLE_DIRECTORY_PAGE_METADATA_SIZE + |
| 207 | + HTABLE_DIRECTORY_ARRAY_SIZE + |
| 208 | + sizeof(page_id_t) * HTABLE_DIRECTORY_ARRAY_SIZE); |
| 209 | + |
| 210 | +static_assert(sizeof(ExtendibleHTableDirectoryPage) <= BUSTUB_PAGE_SIZE); |
| 211 | + |
| 212 | +} // namespace bustub |
0 commit comments