• 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 #include "icing/index/main/posting-list-hit-accessor.h"
16 
17 #include <cstdint>
18 #include <memory>
19 #include <vector>
20 
21 #include "icing/absl_ports/canonical_errors.h"
22 #include "icing/file/posting_list/flash-index-storage.h"
23 #include "icing/file/posting_list/posting-list-identifier.h"
24 #include "icing/file/posting_list/posting-list-used.h"
25 #include "icing/index/main/posting-list-hit-serializer.h"
26 #include "icing/util/status-macros.h"
27 
28 namespace icing {
29 namespace lib {
30 
31 libtextclassifier3::StatusOr<std::unique_ptr<PostingListHitAccessor>>
Create(FlashIndexStorage * storage,PostingListHitSerializer * serializer)32 PostingListHitAccessor::Create(FlashIndexStorage *storage,
33                                PostingListHitSerializer *serializer) {
34   uint32_t max_posting_list_bytes = storage->max_posting_list_bytes();
35   ICING_ASSIGN_OR_RETURN(PostingListUsed in_memory_posting_list,
36                          PostingListUsed::CreateFromUnitializedRegion(
37                              serializer, max_posting_list_bytes));
38   return std::unique_ptr<PostingListHitAccessor>(new PostingListHitAccessor(
39       storage, serializer, std::move(in_memory_posting_list)));
40 }
41 
42 libtextclassifier3::StatusOr<std::unique_ptr<PostingListHitAccessor>>
CreateFromExisting(FlashIndexStorage * storage,PostingListHitSerializer * serializer,PostingListIdentifier existing_posting_list_id)43 PostingListHitAccessor::CreateFromExisting(
44     FlashIndexStorage *storage, PostingListHitSerializer *serializer,
45     PostingListIdentifier existing_posting_list_id) {
46   // Our in_memory_posting_list_ will start as empty.
47   ICING_ASSIGN_OR_RETURN(std::unique_ptr<PostingListHitAccessor> pl_accessor,
48                          Create(storage, serializer));
49   ICING_ASSIGN_OR_RETURN(PostingListHolder holder,
50                          storage->GetPostingList(existing_posting_list_id));
51   pl_accessor->preexisting_posting_list_ =
52       std::make_unique<PostingListHolder>(std::move(holder));
53   return pl_accessor;
54 }
55 
56 // Returns the next batch of hits for the provided posting list.
57 libtextclassifier3::StatusOr<std::vector<Hit>>
GetNextHitsBatch()58 PostingListHitAccessor::GetNextHitsBatch() {
59   if (preexisting_posting_list_ == nullptr) {
60     if (has_reached_posting_list_chain_end_) {
61       return std::vector<Hit>();
62     }
63     return absl_ports::FailedPreconditionError(
64         "Cannot retrieve hits from a PostingListHitAccessor that was not "
65         "created from a preexisting posting list.");
66   }
67   ICING_ASSIGN_OR_RETURN(
68       std::vector<Hit> batch,
69       serializer_->GetHits(&preexisting_posting_list_->posting_list));
70   uint32_t next_block_index = kInvalidBlockIndex;
71   // Posting lists will only be chained when they are max-sized, in which case
72   // next_block_index will point to the next block for the next posting list.
73   // Otherwise, next_block_index can be kInvalidBlockIndex or be used to point
74   // to the next free list block, which is not relevant here.
75   if (preexisting_posting_list_->posting_list.size_in_bytes() ==
76       storage_->max_posting_list_bytes()) {
77     next_block_index = preexisting_posting_list_->next_block_index;
78   }
79 
80   if (next_block_index != kInvalidBlockIndex) {
81     // Since we only have to deal with next block for max-sized posting list
82     // block, max_num_posting_lists is 1 and posting_list_index_bits is
83     // BitsToStore(1).
84     PostingListIdentifier next_posting_list_id(
85         next_block_index, /*posting_list_index=*/0,
86         /*posting_list_index_bits=*/BitsToStore(1));
87     ICING_ASSIGN_OR_RETURN(PostingListHolder holder,
88                            storage_->GetPostingList(next_posting_list_id));
89     preexisting_posting_list_ =
90         std::make_unique<PostingListHolder>(std::move(holder));
91   } else {
92     has_reached_posting_list_chain_end_ = true;
93     preexisting_posting_list_.reset();
94   }
95   return batch;
96 }
97 
PrependHit(const Hit & hit)98 libtextclassifier3::Status PostingListHitAccessor::PrependHit(const Hit &hit) {
99   PostingListUsed &active_pl = (preexisting_posting_list_ != nullptr)
100                                    ? preexisting_posting_list_->posting_list
101                                    : in_memory_posting_list_;
102   libtextclassifier3::Status status = serializer_->PrependHit(&active_pl, hit);
103   if (!absl_ports::IsResourceExhausted(status)) {
104     return status;
105   }
106   // There is no more room to add hits to this current posting list! Therefore,
107   // we need to either move those hits to a larger posting list or flush this
108   // posting list and create another max-sized posting list in the chain.
109   if (preexisting_posting_list_ != nullptr) {
110     ICING_RETURN_IF_ERROR(FlushPreexistingPostingList());
111   } else {
112     ICING_RETURN_IF_ERROR(FlushInMemoryPostingList());
113   }
114 
115   // Re-add hit. Should always fit since we just cleared
116   // in_memory_posting_list_. It's fine to explicitly reference
117   // in_memory_posting_list_ here because there's no way of reaching this line
118   // while preexisting_posting_list_ is still in use.
119   return serializer_->PrependHit(&in_memory_posting_list_, hit);
120 }
121 
122 }  // namespace lib
123 }  // namespace icing
124