1 // Copyright (C) 2019 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #ifndef ICING_FILE_POSTING_LIST_FLASH_INDEX_STORAGE_HEADER_H_ 16 #define ICING_FILE_POSTING_LIST_FLASH_INDEX_STORAGE_HEADER_H_ 17 18 #include <cstdint> 19 #include <memory> 20 21 #include "icing/text_classifier/lib3/utils/base/statusor.h" 22 #include "icing/absl_ports/canonical_errors.h" 23 #include "icing/file/filesystem.h" 24 25 namespace icing { 26 namespace lib { 27 28 // The class used to manage the flash block that contains the header for 29 // FlashIndexStorage. This contains information about the index blocks that 30 // store the posting lists. 31 class HeaderBlock { 32 public: 33 // The class used to access the actual header. 34 struct Header { 35 // A magic used to mark the beginning of a valid header. 36 static constexpr int kMagic = 0xd1b7b293; 37 int magic; 38 int block_size; 39 int last_indexed_docid; 40 // The size of the index_block_infos array. 41 int num_index_block_infos; 42 43 struct IndexBlockInfo { 44 // The size of the posting lists that fit on all the index blocks in this 45 // chain. Each block on this posting list will have posting lists of size 46 // posting_list_bytes. 47 int posting_list_bytes; 48 // The block index of the first block in the free list chain. 49 int free_list_block_index; 50 }; 51 // Variable-size array, num_index_block_infos long. Can have a max length 52 // of log(block_size). This array is used to maintain a free list for the 53 // available blocks. 54 IndexBlockInfo index_block_infos[0]; 55 }; 56 57 // Read HeaderBlock from the specified fd. 58 // 59 // RETURNS: 60 // - HeaderBlock, on success 61 // - INTERNAL if unable to read block_size bytes from fd. Read(const Filesystem * filesystem,int fd,int block_size)62 static libtextclassifier3::StatusOr<HeaderBlock> Read( 63 const Filesystem* filesystem, int fd, int block_size) { 64 std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(block_size); 65 if (!filesystem->PRead(fd, buffer.get(), block_size, 0)) { 66 return absl_ports::InternalError("Unable to reader header block!"); 67 } 68 return HeaderBlock(filesystem, std::move(buffer), block_size); 69 } 70 71 // Make a new HeaderBlock with the specified size. HeaderBlock(const Filesystem * filesystem,int block_size)72 explicit HeaderBlock(const Filesystem* filesystem, int block_size) 73 : HeaderBlock(filesystem, std::make_unique<uint8_t[]>(block_size), 74 block_size) { 75 std::memset(header_buffer_.get(), 0, block_size); 76 } 77 header()78 Header* header() const { 79 return reinterpret_cast<Header*>(header_buffer_.get()); 80 } 81 82 // Add another entry to the index_block_infos array and return a pointer to 83 // that entry. Returns a nullptr if the index_block_infos array is already 84 // at a max size. AddIndexBlockInfo()85 Header::IndexBlockInfo* AddIndexBlockInfo() { 86 if (size() + sizeof(Header::IndexBlockInfo) > block_size_) { 87 return nullptr; 88 } 89 ++header()->num_index_block_infos; 90 return header()->index_block_infos + (header()->num_index_block_infos - 1); 91 } 92 93 // Returns the size of the header block currently in use. size()94 int size() const { 95 return sizeof(Header) + 96 header()->num_index_block_infos * sizeof(Header::IndexBlockInfo); 97 } 98 99 // Writes the header to fd. Returns true on success. Write(int fd)100 bool Write(int fd) { 101 return filesystem_->PWrite(fd, 0, header_buffer_.get(), block_size_); 102 } 103 104 private: HeaderBlock(const Filesystem * filesystem,std::unique_ptr<uint8_t[]> buffer,int block_size)105 explicit HeaderBlock(const Filesystem* filesystem, 106 std::unique_ptr<uint8_t[]> buffer, int block_size) 107 : filesystem_(filesystem), 108 header_buffer_(std::move(buffer)), 109 block_size_(block_size) {} 110 111 const Filesystem* filesystem_; // does NOT own! 112 std::unique_ptr<uint8_t[]> header_buffer_; 113 int block_size_; 114 }; 115 static_assert(16 == sizeof(HeaderBlock::Header), 116 "Header has changed size. Consider how this change might affect " 117 "pre-existing indices."); 118 119 } // namespace lib 120 } // namespace icing 121 122 #endif // ICING_FILE_POSTING_LIST_FLASH_INDEX_STORAGE_HEADER_H_ 123