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