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_INDEX_MAIN_POSTING_LIST_FREE_H_ 16 #define ICING_INDEX_MAIN_POSTING_LIST_FREE_H_ 17 18 #include <sys/mman.h> 19 20 #include <cstdint> 21 #include <cstring> 22 23 #include "icing/text_classifier/lib3/utils/base/statusor.h" 24 #include "icing/absl_ports/canonical_errors.h" 25 #include "icing/index/hit/hit.h" 26 #include "icing/index/main/posting-list-utils.h" 27 #include "icing/legacy/core/icing-string-util.h" 28 #include "icing/util/logging.h" 29 #include "icing/util/status-macros.h" 30 31 namespace icing { 32 namespace lib { 33 34 // A FlashIndexBlock can contain multiple posting lists. This specifies which 35 // PostingList in the FlashIndexBlock we want to refer to. 36 using PostingListIndex = int32_t; 37 inline constexpr PostingListIndex kInvalidPostingListIndex = ~0U; 38 39 // A posting list in the index block's free list. 40 // 41 // We re-use the first sizeof(PostingListIndex) bytes of the posting list 42 // buffer to store a next index for chaining. 43 class PostingListFree { 44 public: 45 // Creates a PostingListFree that points to a buffer of size_in_bytes bytes. 46 // 'Preexisting' means that posting_list_buffer was previously modified by 47 // another instance of PostingListFree. 48 // 49 // Caller owns the posting_list_buffer and must not free it while using 50 // a PostingListFree. 51 // 52 // RETURNS: 53 // - A valid PostingListFree on success 54 // - INVALID_ARGUMENT if size_in_bytes < min_posting_list_size() 55 // || size_in_bytes % sizeof(Hit) != 0. 56 // - FAILED_PRECONDITION if posting_list_buffer is null 57 static libtextclassifier3::StatusOr<PostingListFree> CreateFromPreexistingPostingListFreeRegion(void * posting_list_buffer,uint32_t size_in_bytes)58 CreateFromPreexistingPostingListFreeRegion(void *posting_list_buffer, 59 uint32_t size_in_bytes) { 60 ICING_RETURN_ERROR_IF_NULL(posting_list_buffer); 61 if (!posting_list_utils::IsValidPostingListSize(size_in_bytes)) { 62 return absl_ports::InvalidArgumentError(IcingStringUtil::StringPrintf( 63 "Requested posting list size %d is invalid!", size_in_bytes)); 64 } 65 return PostingListFree(posting_list_buffer, size_in_bytes); 66 } 67 68 // Creates a PostingListFree that points to a buffer of size_in_bytes bytes 69 // and initializes the content of the buffer so that the returned 70 // PostingListFree is empty. 71 // 72 // Caller owns the posting_list_buffer buffer and must not free it while using 73 // a PostingListFree. 74 // 75 // RETURNS: 76 // - A valid PostingListFree on success 77 // - INVALID_ARGUMENT if size_in_bytes < min_size() || size_in_bytes % 78 // sizeof(Hit) != 0. 79 // - FAILED_PRECONDITION if posting_list_buffer is null 80 static libtextclassifier3::StatusOr<PostingListFree> CreateFromUnitializedRegion(void * posting_list_buffer,uint32_t size_in_bytes)81 CreateFromUnitializedRegion(void *posting_list_buffer, 82 uint32_t size_in_bytes) { 83 ICING_ASSIGN_OR_RETURN(PostingListFree posting_list_free, 84 CreateFromPreexistingPostingListFreeRegion( 85 posting_list_buffer, size_in_bytes)); 86 posting_list_free.Clear(); 87 return posting_list_free; 88 } 89 90 // Used to store/access the index of the next free posting list in this 91 // index block. get_next_posting_list_index()92 PostingListIndex get_next_posting_list_index() const { 93 PostingListIndex posting_list_index; 94 memcpy(&posting_list_index, posting_list_buffer_, 95 sizeof(posting_list_index)); 96 return posting_list_index; 97 } set_next_posting_list_index(PostingListIndex posting_list_index)98 void set_next_posting_list_index(PostingListIndex posting_list_index) { 99 memcpy(posting_list_buffer_, &posting_list_index, 100 sizeof(posting_list_index)); 101 } 102 103 private: PostingListFree(void * posting_list_buffer,uint32_t size_in_bytes)104 PostingListFree(void *posting_list_buffer, uint32_t size_in_bytes) 105 : posting_list_buffer_(static_cast<uint8_t *>(posting_list_buffer)), 106 size_in_bytes_(size_in_bytes) {} 107 108 // Reset the current free posting list as unchained free posting list so that 109 // there's no next posting list index. This *must* be called if the 110 // posting_list_buffer_ region was never used for a previous instance of 111 // PostingListFree. Clear()112 void Clear() { set_next_posting_list_index(kInvalidPostingListIndex); } 113 114 // A byte array of size size_in_bytes_. The first sizeof(PostingListIndex) 115 // bytes which will store the next posting list index, the rest are unused and 116 // can be anything. 117 uint8_t *posting_list_buffer_; 118 [[maybe_unused]] uint32_t size_in_bytes_; 119 120 static_assert(sizeof(PostingListIndex) <= 121 posting_list_utils::min_posting_list_size(), 122 "PostingListIndex must be small enough to fit in a " 123 "minimum-sized Posting List."); 124 }; 125 126 } // namespace lib 127 } // namespace icing 128 129 #endif // ICING_INDEX_MAIN_POSTING_LIST_FREE_H_ 130