• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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