• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 2022 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/file/posting_list/posting-list-accessor.h"
16 
17 #include <cstdint>
18 #include <memory>
19 
20 #include "icing/absl_ports/canonical_errors.h"
21 #include "icing/file/posting_list/flash-index-storage.h"
22 #include "icing/file/posting_list/posting-list-identifier.h"
23 #include "icing/file/posting_list/posting-list-used.h"
24 #include "icing/util/status-macros.h"
25 
26 namespace icing {
27 namespace lib {
28 
FlushPreexistingPostingList()29 libtextclassifier3::Status PostingListAccessor::FlushPreexistingPostingList() {
30   if (preexisting_posting_list_->posting_list.size_in_bytes() ==
31       storage_->max_posting_list_bytes()) {
32     // If this is a max-sized posting list, then sync to disk and keep track of
33     // the id.
34     ICING_RETURN_IF_ERROR(
35         storage_->WritePostingListToDisk(*preexisting_posting_list_));
36     prev_block_identifier_ = preexisting_posting_list_->id;
37   } else {
38     // If this is NOT a max-sized posting list, then our data have outgrown this
39     // particular posting list. Move the data into the in-memory posting list
40     // and free this posting list.
41     //
42     // Move will always succeed since in_memory_posting_list_ is max_pl_bytes.
43     GetSerializer()->MoveFrom(/*dst=*/&in_memory_posting_list_,
44                               /*src=*/&preexisting_posting_list_->posting_list);
45 
46     // Now that all the contents of this posting list have been copied, there's
47     // no more use for it. Make it available to be used for another posting
48     // list.
49     storage_->FreePostingList(std::move(*preexisting_posting_list_));
50   }
51   preexisting_posting_list_.reset();
52   return libtextclassifier3::Status::OK;
53 }
54 
FlushInMemoryPostingList()55 libtextclassifier3::Status PostingListAccessor::FlushInMemoryPostingList() {
56   // We exceeded max_pl_bytes(). Need to flush in_memory_posting_list_ and
57   // update the chain.
58   ICING_ASSIGN_OR_RETURN(PostingListHolder holder,
59                          storage_->AllocateAndChainMaxSizePostingList(
60                              prev_block_identifier_.block_index()));
61   ICING_RETURN_IF_ERROR(
62       GetSerializer()->MoveFrom(/*dst=*/&holder.posting_list,
63                                 /*src=*/&in_memory_posting_list_));
64   ICING_RETURN_IF_ERROR(storage_->WritePostingListToDisk(holder));
65 
66   // Set prev block id only if persist to disk succeeded.
67   prev_block_identifier_ = holder.id;
68   return libtextclassifier3::Status::OK;
69 }
70 
Finalize()71 PostingListAccessor::FinalizeResult PostingListAccessor::Finalize() && {
72   if (preexisting_posting_list_ != nullptr) {
73     // Sync to disk.
74     return FinalizeResult(
75         storage_->WritePostingListToDisk(*preexisting_posting_list_),
76         preexisting_posting_list_->id);
77   }
78 
79   if (GetSerializer()->GetBytesUsed(&in_memory_posting_list_) <= 0) {
80     return FinalizeResult(absl_ports::InvalidArgumentError(
81                               "Can't finalize an empty PostingListAccessor. "
82                               "There's nothing to Finalize!"),
83                           PostingListIdentifier::kInvalid);
84   }
85 
86   libtextclassifier3::StatusOr<PostingListHolder> holder_or;
87   if (prev_block_identifier_.is_valid()) {
88     // If prev_block_identifier_ is valid, then it means there was a max-sized
89     // posting list, so we have to allocate another new max size posting list
90     // and chain them together.
91     holder_or = storage_->AllocateAndChainMaxSizePostingList(
92         prev_block_identifier_.block_index());
93   } else {
94     // Otherwise, it is the first posting list, and we can use smaller size pl.
95     // Note that even if it needs a max-sized posting list here, it is ok to
96     // call AllocatePostingList without setting next block index since we don't
97     // have any previous posting list to chain and AllocatePostingList will set
98     // next block index to kInvalidBlockIndex.
99     uint32_t posting_list_bytes =
100         GetSerializer()->GetMinPostingListSizeToFit(&in_memory_posting_list_);
101     holder_or = storage_->AllocatePostingList(posting_list_bytes);
102   }
103 
104   if (!holder_or.ok()) {
105     return FinalizeResult(std::move(holder_or).status(),
106                           prev_block_identifier_);
107   }
108   PostingListHolder holder = std::move(holder_or).ValueOrDie();
109 
110   // Move to allocated area. This should never actually return an error. We know
111   // that editor.posting_list() is valid because it wouldn't have successfully
112   // returned by AllocatePostingList if it wasn't. We know
113   // in_memory_posting_list_ is valid because we created it in-memory. And
114   // finally, we know that the data from in_memory_posting_list_ will fit in
115   // editor.posting_list() because we requested it be at at least
116   // posting_list_bytes large.
117   auto status = GetSerializer()->MoveFrom(/*dst=*/&holder.posting_list,
118                                           /*src=*/&in_memory_posting_list_);
119   if (!status.ok()) {
120     return FinalizeResult(std::move(status), prev_block_identifier_);
121   }
122 
123   status = storage_->WritePostingListToDisk(holder);
124   if (!status.ok()) {
125     return FinalizeResult(std::move(status), prev_block_identifier_);
126   }
127   return FinalizeResult(libtextclassifier3::Status::OK, holder.id);
128 }
129 
130 }  // namespace lib
131 }  // namespace icing
132