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/join/posting-list-join-data-serializer.h"
16
17 #include <algorithm>
18 #include <iterator>
19 #include <vector>
20
21 #include "icing/text_classifier/lib3/utils/base/status.h"
22 #include "gmock/gmock.h"
23 #include "gtest/gtest.h"
24 #include "icing/file/posting_list/posting-list-used.h"
25 #include "icing/join/document-id-to-join-info.h"
26 #include "icing/store/namespace-id-fingerprint.h"
27 #include "icing/testing/common-matchers.h"
28
29 using testing::ElementsAre;
30 using testing::ElementsAreArray;
31 using testing::Eq;
32 using testing::IsEmpty;
33 using testing::SizeIs;
34
35 namespace icing {
36 namespace lib {
37
38 namespace {
39
TEST(PostingListJoinDataSerializerTest,GetMinPostingListSizeToFitNotNull)40 TEST(PostingListJoinDataSerializerTest, GetMinPostingListSizeToFitNotNull) {
41 PostingListJoinDataSerializer<DocumentIdToJoinInfo<NamespaceIdFingerprint>>
42 serializer;
43
44 int size = 2551 * sizeof(DocumentIdToJoinInfo<NamespaceIdFingerprint>);
45 ICING_ASSERT_OK_AND_ASSIGN(
46 PostingListUsed pl_used,
47 PostingListUsed::CreateFromUnitializedRegion(&serializer, size));
48
49 ASSERT_THAT(serializer.PrependData(
50 &pl_used, DocumentIdToJoinInfo<NamespaceIdFingerprint>(
51 /*document_id=*/0,
52 NamespaceIdFingerprint(/*namespace_id=*/1,
53 /*fingerprint=*/2))),
54 IsOk());
55 EXPECT_THAT(serializer.GetMinPostingListSizeToFit(&pl_used),
56 Eq(2 * sizeof(DocumentIdToJoinInfo<NamespaceIdFingerprint>)));
57
58 ASSERT_THAT(serializer.PrependData(
59 &pl_used, DocumentIdToJoinInfo<NamespaceIdFingerprint>(
60 /*document_id=*/1,
61 NamespaceIdFingerprint(/*namespace_id=*/1,
62 /*fingerprint=*/5))),
63 IsOk());
64 EXPECT_THAT(serializer.GetMinPostingListSizeToFit(&pl_used),
65 Eq(3 * sizeof(DocumentIdToJoinInfo<NamespaceIdFingerprint>)));
66 }
67
TEST(PostingListJoinDataSerializerTest,GetMinPostingListSizeToFitAlmostFull)68 TEST(PostingListJoinDataSerializerTest, GetMinPostingListSizeToFitAlmostFull) {
69 PostingListJoinDataSerializer<DocumentIdToJoinInfo<NamespaceIdFingerprint>>
70 serializer;
71
72 int size = 3 * sizeof(DocumentIdToJoinInfo<NamespaceIdFingerprint>);
73 ICING_ASSERT_OK_AND_ASSIGN(
74 PostingListUsed pl_used,
75 PostingListUsed::CreateFromUnitializedRegion(&serializer, size));
76
77 ASSERT_THAT(serializer.PrependData(
78 &pl_used, DocumentIdToJoinInfo<NamespaceIdFingerprint>(
79 /*document_id=*/0,
80 NamespaceIdFingerprint(/*namespace_id=*/1,
81 /*fingerprint=*/2))),
82 IsOk());
83 ASSERT_THAT(serializer.PrependData(
84 &pl_used, DocumentIdToJoinInfo<NamespaceIdFingerprint>(
85 /*document_id=*/1,
86 NamespaceIdFingerprint(/*namespace_id=*/1,
87 /*fingerprint=*/5))),
88 IsOk());
89 EXPECT_THAT(serializer.GetMinPostingListSizeToFit(&pl_used), Eq(size));
90 }
91
TEST(PostingListJoinDataSerializerTest,GetMinPostingListSizeToFitFull)92 TEST(PostingListJoinDataSerializerTest, GetMinPostingListSizeToFitFull) {
93 PostingListJoinDataSerializer<DocumentIdToJoinInfo<NamespaceIdFingerprint>>
94 serializer;
95
96 int size = 3 * sizeof(DocumentIdToJoinInfo<NamespaceIdFingerprint>);
97 ICING_ASSERT_OK_AND_ASSIGN(
98 PostingListUsed pl_used,
99 PostingListUsed::CreateFromUnitializedRegion(&serializer, size));
100
101 ASSERT_THAT(serializer.PrependData(
102 &pl_used, DocumentIdToJoinInfo<NamespaceIdFingerprint>(
103 /*document_id=*/0,
104 NamespaceIdFingerprint(/*namespace_id=*/1,
105 /*fingerprint=*/2))),
106 IsOk());
107 ASSERT_THAT(serializer.PrependData(
108 &pl_used, DocumentIdToJoinInfo<NamespaceIdFingerprint>(
109 /*document_id=*/1,
110 NamespaceIdFingerprint(/*namespace_id=*/1,
111 /*fingerprint=*/5))),
112 IsOk());
113 ASSERT_THAT(serializer.PrependData(
114 &pl_used, DocumentIdToJoinInfo<NamespaceIdFingerprint>(
115 /*document_id=*/2,
116 NamespaceIdFingerprint(/*namespace_id=*/1,
117 /*fingerprint=*/10))),
118 IsOk());
119 EXPECT_THAT(serializer.GetMinPostingListSizeToFit(&pl_used), Eq(size));
120 }
121
TEST(PostingListJoinDataSerializerTest,PrependDataNotFull)122 TEST(PostingListJoinDataSerializerTest, PrependDataNotFull) {
123 PostingListJoinDataSerializer<DocumentIdToJoinInfo<NamespaceIdFingerprint>>
124 serializer;
125
126 int size = 2551 * sizeof(DocumentIdToJoinInfo<NamespaceIdFingerprint>);
127 ICING_ASSERT_OK_AND_ASSIGN(
128 PostingListUsed pl_used,
129 PostingListUsed::CreateFromUnitializedRegion(&serializer, size));
130
131 // Make used.
132 DocumentIdToJoinInfo<NamespaceIdFingerprint> data0(
133 /*document_id=*/0,
134 NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/2));
135 EXPECT_THAT(serializer.PrependData(&pl_used, data0), IsOk());
136 // Size = sizeof(uncompressed data0)
137 int expected_size = sizeof(DocumentIdToJoinInfo<NamespaceIdFingerprint>);
138 EXPECT_THAT(serializer.GetBytesUsed(&pl_used), Eq(expected_size));
139 EXPECT_THAT(serializer.GetData(&pl_used), IsOkAndHolds(ElementsAre(data0)));
140
141 DocumentIdToJoinInfo<NamespaceIdFingerprint> data1(
142 /*document_id=*/1,
143 NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/5));
144 EXPECT_THAT(serializer.PrependData(&pl_used, data1), IsOk());
145 // Size = sizeof(uncompressed data1)
146 // + sizeof(uncompressed data0)
147 expected_size += sizeof(DocumentIdToJoinInfo<NamespaceIdFingerprint>);
148 EXPECT_THAT(serializer.GetBytesUsed(&pl_used), Eq(expected_size));
149 EXPECT_THAT(serializer.GetData(&pl_used),
150 IsOkAndHolds(ElementsAre(data1, data0)));
151
152 DocumentIdToJoinInfo<NamespaceIdFingerprint> data2(
153 /*document_id=*/2,
154 NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/10));
155 EXPECT_THAT(serializer.PrependData(&pl_used, data2), IsOk());
156 // Size = sizeof(uncompressed data2)
157 // + sizeof(uncompressed data1)
158 // + sizeof(uncompressed data0)
159 expected_size += sizeof(DocumentIdToJoinInfo<NamespaceIdFingerprint>);
160 EXPECT_THAT(serializer.GetBytesUsed(&pl_used), Eq(expected_size));
161 EXPECT_THAT(serializer.GetData(&pl_used),
162 IsOkAndHolds(ElementsAre(data2, data1, data0)));
163 }
164
TEST(PostingListJoinDataSerializerTest,PrependDataAlmostFull)165 TEST(PostingListJoinDataSerializerTest, PrependDataAlmostFull) {
166 PostingListJoinDataSerializer<DocumentIdToJoinInfo<NamespaceIdFingerprint>>
167 serializer;
168
169 int size = 4 * sizeof(DocumentIdToJoinInfo<NamespaceIdFingerprint>);
170 ICING_ASSERT_OK_AND_ASSIGN(
171 PostingListUsed pl_used,
172 PostingListUsed::CreateFromUnitializedRegion(&serializer, size));
173
174 // Fill up the compressed region.
175 // Transitions:
176 // Adding data0: EMPTY -> NOT_FULL
177 // Adding data1: NOT_FULL -> NOT_FULL
178 DocumentIdToJoinInfo<NamespaceIdFingerprint> data0(
179 /*document_id=*/0,
180 NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/2));
181 DocumentIdToJoinInfo<NamespaceIdFingerprint> data1(
182 /*document_id=*/1,
183 NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/5));
184 EXPECT_THAT(serializer.PrependData(&pl_used, data0), IsOk());
185 EXPECT_THAT(serializer.PrependData(&pl_used, data1), IsOk());
186 int expected_size = 2 * sizeof(DocumentIdToJoinInfo<NamespaceIdFingerprint>);
187 EXPECT_THAT(serializer.GetBytesUsed(&pl_used), Eq(expected_size));
188 EXPECT_THAT(serializer.GetData(&pl_used),
189 IsOkAndHolds(ElementsAre(data1, data0)));
190
191 // Add one more data to transition NOT_FULL -> ALMOST_FULL
192 DocumentIdToJoinInfo<NamespaceIdFingerprint> data2(
193 /*document_id=*/2,
194 NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/10));
195 EXPECT_THAT(serializer.PrependData(&pl_used, data2), IsOk());
196 expected_size = 3 * sizeof(DocumentIdToJoinInfo<NamespaceIdFingerprint>);
197 EXPECT_THAT(serializer.GetBytesUsed(&pl_used), Eq(expected_size));
198 EXPECT_THAT(serializer.GetData(&pl_used),
199 IsOkAndHolds(ElementsAre(data2, data1, data0)));
200
201 // Add one more data to transition ALMOST_FULL -> FULL
202 DocumentIdToJoinInfo<NamespaceIdFingerprint> data3(
203 /*document_id=*/3,
204 NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/0));
205 EXPECT_THAT(serializer.PrependData(&pl_used, data3), IsOk());
206 EXPECT_THAT(serializer.GetBytesUsed(&pl_used), Eq(size));
207 EXPECT_THAT(serializer.GetData(&pl_used),
208 IsOkAndHolds(ElementsAre(data3, data2, data1, data0)));
209
210 // The posting list is FULL. Adding another data should fail.
211 DocumentIdToJoinInfo<NamespaceIdFingerprint> data4(
212 /*document_id=*/4,
213 NamespaceIdFingerprint(/*namespace_id=*/0, /*fingerprint=*/1234));
214 EXPECT_THAT(serializer.PrependData(&pl_used, data4),
215 StatusIs(libtextclassifier3::StatusCode::RESOURCE_EXHAUSTED));
216 }
217
TEST(PostingListJoinDataSerializerTest,PrependSmallerDataShouldFail)218 TEST(PostingListJoinDataSerializerTest, PrependSmallerDataShouldFail) {
219 PostingListJoinDataSerializer<DocumentIdToJoinInfo<NamespaceIdFingerprint>>
220 serializer;
221
222 int size = 4 * sizeof(DocumentIdToJoinInfo<NamespaceIdFingerprint>);
223 ICING_ASSERT_OK_AND_ASSIGN(
224 PostingListUsed pl_used,
225 PostingListUsed::CreateFromUnitializedRegion(&serializer, size));
226
227 DocumentIdToJoinInfo<NamespaceIdFingerprint> data(
228 /*document_id=*/100,
229 NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/2));
230 DocumentIdToJoinInfo<NamespaceIdFingerprint> smaller_data(
231 /*document_id=*/99,
232 NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/2));
233
234 // NOT_FULL -> NOT_FULL
235 ASSERT_THAT(serializer.PrependData(&pl_used, data), IsOk());
236 EXPECT_THAT(serializer.PrependData(&pl_used, smaller_data),
237 StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT));
238
239 // NOT_FULL -> ALMOST_FULL
240 ASSERT_THAT(serializer.PrependData(&pl_used, data), IsOk());
241 EXPECT_THAT(serializer.PrependData(&pl_used, smaller_data),
242 StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT));
243
244 // ALMOST_FULL -> FULL
245 ASSERT_THAT(serializer.PrependData(&pl_used, data), IsOk());
246 EXPECT_THAT(serializer.PrependData(&pl_used, smaller_data),
247 StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT));
248 }
249
TEST(PostingListJoinDataSerializerTest,PrependDataPostingListUsedMinSize)250 TEST(PostingListJoinDataSerializerTest, PrependDataPostingListUsedMinSize) {
251 PostingListJoinDataSerializer<DocumentIdToJoinInfo<NamespaceIdFingerprint>>
252 serializer;
253
254 int size = serializer.GetMinPostingListSize();
255 ICING_ASSERT_OK_AND_ASSIGN(
256 PostingListUsed pl_used,
257 PostingListUsed::CreateFromUnitializedRegion(&serializer, size));
258
259 // PL State: EMPTY
260 EXPECT_THAT(serializer.GetBytesUsed(&pl_used), Eq(0));
261 EXPECT_THAT(serializer.GetData(&pl_used), IsOkAndHolds(IsEmpty()));
262
263 // Add a data. PL should shift to ALMOST_FULL state
264 DocumentIdToJoinInfo<NamespaceIdFingerprint> data0(
265 /*document_id=*/0,
266 NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/2));
267 EXPECT_THAT(serializer.PrependData(&pl_used, data0), IsOk());
268 // Size = sizeof(uncompressed data0)
269 int expected_size = sizeof(DocumentIdToJoinInfo<NamespaceIdFingerprint>);
270 EXPECT_THAT(serializer.GetBytesUsed(&pl_used), Eq(expected_size));
271 EXPECT_THAT(serializer.GetData(&pl_used), IsOkAndHolds(ElementsAre(data0)));
272
273 // Add another data. PL should shift to FULL state.
274 DocumentIdToJoinInfo<NamespaceIdFingerprint> data1(
275 /*document_id=*/1,
276 NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/5));
277 EXPECT_THAT(serializer.PrependData(&pl_used, data1), IsOk());
278 // Size = sizeof(uncompressed data1) + sizeof(uncompressed data0)
279 expected_size += sizeof(DocumentIdToJoinInfo<NamespaceIdFingerprint>);
280 EXPECT_THAT(serializer.GetBytesUsed(&pl_used), Eq(expected_size));
281 EXPECT_THAT(serializer.GetData(&pl_used),
282 IsOkAndHolds(ElementsAre(data1, data0)));
283
284 // The posting list is FULL. Adding another data should fail.
285 DocumentIdToJoinInfo<NamespaceIdFingerprint> data2(
286 /*document_id=*/2,
287 NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/10));
288 EXPECT_THAT(serializer.PrependData(&pl_used, data2),
289 StatusIs(libtextclassifier3::StatusCode::RESOURCE_EXHAUSTED));
290 }
291
TEST(PostingListJoinDataSerializerTest,PrependDataArrayDoNotKeepPrepended)292 TEST(PostingListJoinDataSerializerTest, PrependDataArrayDoNotKeepPrepended) {
293 PostingListJoinDataSerializer<DocumentIdToJoinInfo<NamespaceIdFingerprint>>
294 serializer;
295
296 int size = 6 * sizeof(DocumentIdToJoinInfo<NamespaceIdFingerprint>);
297 ICING_ASSERT_OK_AND_ASSIGN(
298 PostingListUsed pl_used,
299 PostingListUsed::CreateFromUnitializedRegion(&serializer, size));
300
301 std::vector<DocumentIdToJoinInfo<NamespaceIdFingerprint>> data_in;
302 std::vector<DocumentIdToJoinInfo<NamespaceIdFingerprint>> data_pushed;
303
304 // Add 3 data. The PL is in the empty state and should be able to fit all 3
305 // data without issue, transitioning the PL from EMPTY -> NOT_FULL.
306 data_in.push_back(DocumentIdToJoinInfo<NamespaceIdFingerprint>(
307 /*document_id=*/0,
308 NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/2)));
309 data_in.push_back(DocumentIdToJoinInfo<NamespaceIdFingerprint>(
310 /*document_id=*/1,
311 NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/5)));
312 data_in.push_back(DocumentIdToJoinInfo<NamespaceIdFingerprint>(
313 /*document_id=*/2,
314 NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/10)));
315 EXPECT_THAT(
316 serializer.PrependDataArray(&pl_used, data_in.data(), data_in.size(),
317 /*keep_prepended=*/false),
318 IsOkAndHolds(data_in.size()));
319 std::move(data_in.begin(), data_in.end(), std::back_inserter(data_pushed));
320 EXPECT_THAT(serializer.GetBytesUsed(&pl_used),
321 Eq(data_pushed.size() *
322 sizeof(DocumentIdToJoinInfo<NamespaceIdFingerprint>)));
323 EXPECT_THAT(
324 serializer.GetData(&pl_used),
325 IsOkAndHolds(ElementsAreArray(data_pushed.rbegin(), data_pushed.rend())));
326
327 // Add 2 data. The PL should transition from NOT_FULL to ALMOST_FULL.
328 data_in.clear();
329 data_in.push_back(DocumentIdToJoinInfo<NamespaceIdFingerprint>(
330 /*document_id=*/3,
331 NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/0)));
332 data_in.push_back(DocumentIdToJoinInfo<NamespaceIdFingerprint>(
333 /*document_id=*/4,
334 NamespaceIdFingerprint(/*namespace_id=*/0, /*fingerprint=*/1234)));
335 EXPECT_THAT(
336 serializer.PrependDataArray(&pl_used, data_in.data(), data_in.size(),
337 /*keep_prepended=*/false),
338 IsOkAndHolds(data_in.size()));
339 std::move(data_in.begin(), data_in.end(), std::back_inserter(data_pushed));
340 EXPECT_THAT(serializer.GetBytesUsed(&pl_used),
341 Eq(data_pushed.size() *
342 sizeof(DocumentIdToJoinInfo<NamespaceIdFingerprint>)));
343 EXPECT_THAT(
344 serializer.GetData(&pl_used),
345 IsOkAndHolds(ElementsAreArray(data_pushed.rbegin(), data_pushed.rend())));
346
347 // Add 2 data. The PL should remain ALMOST_FULL since the remaining space can
348 // only fit 1 data.
349 data_in.clear();
350 data_in.push_back(DocumentIdToJoinInfo<NamespaceIdFingerprint>(
351 /*document_id=*/5,
352 NamespaceIdFingerprint(/*namespace_id=*/2, /*fingerprint=*/99)));
353 data_in.push_back(DocumentIdToJoinInfo<NamespaceIdFingerprint>(
354 /*document_id=*/6,
355 NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/63)));
356 EXPECT_THAT(
357 serializer.PrependDataArray(&pl_used, data_in.data(), data_in.size(),
358 /*keep_prepended=*/false),
359 IsOkAndHolds(0));
360 EXPECT_THAT(serializer.GetBytesUsed(&pl_used),
361 Eq(data_pushed.size() *
362 sizeof(DocumentIdToJoinInfo<NamespaceIdFingerprint>)));
363 EXPECT_THAT(
364 serializer.GetData(&pl_used),
365 IsOkAndHolds(ElementsAreArray(data_pushed.rbegin(), data_pushed.rend())));
366
367 // Add 1 data. The PL should transition from ALMOST_FULL to FULL.
368 data_in.pop_back();
369 ASSERT_THAT(data_in, SizeIs(1));
370 EXPECT_THAT(
371 serializer.PrependDataArray(&pl_used, data_in.data(), data_in.size(),
372 /*keep_prepended=*/false),
373 IsOkAndHolds(data_in.size()));
374 std::move(data_in.begin(), data_in.end(), std::back_inserter(data_pushed));
375 EXPECT_THAT(serializer.GetBytesUsed(&pl_used),
376 Eq(data_pushed.size() *
377 sizeof(DocumentIdToJoinInfo<NamespaceIdFingerprint>)));
378 EXPECT_THAT(
379 serializer.GetData(&pl_used),
380 IsOkAndHolds(ElementsAreArray(data_pushed.rbegin(), data_pushed.rend())));
381 }
382
TEST(PostingListJoinDataSerializerTest,PrependDataArrayKeepPrepended)383 TEST(PostingListJoinDataSerializerTest, PrependDataArrayKeepPrepended) {
384 PostingListJoinDataSerializer<DocumentIdToJoinInfo<NamespaceIdFingerprint>>
385 serializer;
386
387 int size = 6 * sizeof(DocumentIdToJoinInfo<NamespaceIdFingerprint>);
388 ICING_ASSERT_OK_AND_ASSIGN(
389 PostingListUsed pl_used,
390 PostingListUsed::CreateFromUnitializedRegion(&serializer, size));
391
392 std::vector<DocumentIdToJoinInfo<NamespaceIdFingerprint>> data_in;
393 std::vector<DocumentIdToJoinInfo<NamespaceIdFingerprint>> data_pushed;
394
395 // Add 3 data. The PL is in the empty state and should be able to fit all 3
396 // data without issue, transitioning the PL from EMPTY -> NOT_FULL.
397 data_in.push_back(DocumentIdToJoinInfo<NamespaceIdFingerprint>(
398 /*document_id=*/0,
399 NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/2)));
400 data_in.push_back(DocumentIdToJoinInfo<NamespaceIdFingerprint>(
401 /*document_id=*/1,
402 NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/5)));
403 data_in.push_back(DocumentIdToJoinInfo<NamespaceIdFingerprint>(
404 /*document_id=*/2,
405 NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/10)));
406 EXPECT_THAT(
407 serializer.PrependDataArray(&pl_used, data_in.data(), data_in.size(),
408 /*keep_prepended=*/true),
409 IsOkAndHolds(data_in.size()));
410 std::move(data_in.begin(), data_in.end(), std::back_inserter(data_pushed));
411 EXPECT_THAT(serializer.GetBytesUsed(&pl_used),
412 Eq(data_pushed.size() *
413 sizeof(DocumentIdToJoinInfo<NamespaceIdFingerprint>)));
414 EXPECT_THAT(
415 serializer.GetData(&pl_used),
416 IsOkAndHolds(ElementsAreArray(data_pushed.rbegin(), data_pushed.rend())));
417
418 // Add 4 data. The PL should prepend 3 data and transition from NOT_FULL to
419 // FULL.
420 data_in.clear();
421 data_in.push_back(DocumentIdToJoinInfo<NamespaceIdFingerprint>(
422 /*document_id=*/3,
423 NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/0)));
424 data_in.push_back(DocumentIdToJoinInfo<NamespaceIdFingerprint>(
425 /*document_id=*/4,
426 NamespaceIdFingerprint(/*namespace_id=*/0, /*fingerprint=*/1234)));
427 data_in.push_back(DocumentIdToJoinInfo<NamespaceIdFingerprint>(
428 /*document_id=*/5,
429 NamespaceIdFingerprint(/*namespace_id=*/2, /*fingerprint=*/99)));
430 data_in.push_back(DocumentIdToJoinInfo<NamespaceIdFingerprint>(
431 /*document_id=*/6,
432 NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/63)));
433 EXPECT_THAT(
434 serializer.PrependDataArray(&pl_used, data_in.data(), data_in.size(),
435 /*keep_prepended=*/true),
436 IsOkAndHolds(3));
437 data_in.pop_back();
438 ASSERT_THAT(data_in, SizeIs(3));
439 std::move(data_in.begin(), data_in.end(), std::back_inserter(data_pushed));
440 EXPECT_THAT(serializer.GetBytesUsed(&pl_used),
441 Eq(data_pushed.size() *
442 sizeof(DocumentIdToJoinInfo<NamespaceIdFingerprint>)));
443 EXPECT_THAT(
444 serializer.GetData(&pl_used),
445 IsOkAndHolds(ElementsAreArray(data_pushed.rbegin(), data_pushed.rend())));
446 }
447
TEST(PostingListJoinDataSerializerTest,MoveFrom)448 TEST(PostingListJoinDataSerializerTest, MoveFrom) {
449 PostingListJoinDataSerializer<DocumentIdToJoinInfo<NamespaceIdFingerprint>>
450 serializer;
451
452 int size = 3 * serializer.GetMinPostingListSize();
453 ICING_ASSERT_OK_AND_ASSIGN(
454 PostingListUsed pl_used1,
455 PostingListUsed::CreateFromUnitializedRegion(&serializer, size));
456
457 std::vector<DocumentIdToJoinInfo<NamespaceIdFingerprint>> data_arr1 = {
458 DocumentIdToJoinInfo<NamespaceIdFingerprint>(
459 /*document_id=*/0,
460 NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/2)),
461 DocumentIdToJoinInfo<NamespaceIdFingerprint>(
462 /*document_id=*/1,
463 NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/5))};
464 ASSERT_THAT(
465 serializer.PrependDataArray(&pl_used1, data_arr1.data(), data_arr1.size(),
466 /*keep_prepended=*/false),
467 IsOkAndHolds(data_arr1.size()));
468
469 ICING_ASSERT_OK_AND_ASSIGN(
470 PostingListUsed pl_used2,
471 PostingListUsed::CreateFromUnitializedRegion(&serializer, size));
472 std::vector<DocumentIdToJoinInfo<NamespaceIdFingerprint>> data_arr2 = {
473 DocumentIdToJoinInfo<NamespaceIdFingerprint>(
474 /*document_id=*/2,
475 NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/10)),
476 DocumentIdToJoinInfo<NamespaceIdFingerprint>(
477 /*document_id=*/3,
478 NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/0)),
479 DocumentIdToJoinInfo<NamespaceIdFingerprint>(
480 /*document_id=*/4,
481 NamespaceIdFingerprint(/*namespace_id=*/0, /*fingerprint=*/1234)),
482 DocumentIdToJoinInfo<NamespaceIdFingerprint>(
483 /*document_id=*/5,
484 NamespaceIdFingerprint(/*namespace_id=*/2, /*fingerprint=*/99))};
485 ASSERT_THAT(
486 serializer.PrependDataArray(&pl_used2, data_arr2.data(), data_arr2.size(),
487 /*keep_prepended=*/false),
488 IsOkAndHolds(data_arr2.size()));
489
490 EXPECT_THAT(serializer.MoveFrom(/*dst=*/&pl_used2, /*src=*/&pl_used1),
491 IsOk());
492 EXPECT_THAT(
493 serializer.GetData(&pl_used2),
494 IsOkAndHolds(ElementsAreArray(data_arr1.rbegin(), data_arr1.rend())));
495 EXPECT_THAT(serializer.GetData(&pl_used1), IsOkAndHolds(IsEmpty()));
496 }
497
TEST(PostingListJoinDataSerializerTest,MoveToNullReturnsFailedPrecondition)498 TEST(PostingListJoinDataSerializerTest, MoveToNullReturnsFailedPrecondition) {
499 PostingListJoinDataSerializer<DocumentIdToJoinInfo<NamespaceIdFingerprint>>
500 serializer;
501
502 int size = 3 * serializer.GetMinPostingListSize();
503 ICING_ASSERT_OK_AND_ASSIGN(
504 PostingListUsed pl_used,
505 PostingListUsed::CreateFromUnitializedRegion(&serializer, size));
506 std::vector<DocumentIdToJoinInfo<NamespaceIdFingerprint>> data_arr = {
507 DocumentIdToJoinInfo<NamespaceIdFingerprint>(
508 /*document_id=*/0,
509 NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/2)),
510 DocumentIdToJoinInfo<NamespaceIdFingerprint>(
511 /*document_id=*/1,
512 NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/5))};
513 ASSERT_THAT(
514 serializer.PrependDataArray(&pl_used, data_arr.data(), data_arr.size(),
515 /*keep_prepended=*/false),
516 IsOkAndHolds(data_arr.size()));
517
518 EXPECT_THAT(serializer.MoveFrom(/*dst=*/&pl_used, /*src=*/nullptr),
519 StatusIs(libtextclassifier3::StatusCode::FAILED_PRECONDITION));
520 EXPECT_THAT(
521 serializer.GetData(&pl_used),
522 IsOkAndHolds(ElementsAreArray(data_arr.rbegin(), data_arr.rend())));
523
524 EXPECT_THAT(serializer.MoveFrom(/*dst=*/nullptr, /*src=*/&pl_used),
525 StatusIs(libtextclassifier3::StatusCode::FAILED_PRECONDITION));
526 EXPECT_THAT(
527 serializer.GetData(&pl_used),
528 IsOkAndHolds(ElementsAreArray(data_arr.rbegin(), data_arr.rend())));
529 }
530
TEST(PostingListJoinDataSerializerTest,MoveToPostingListTooSmall)531 TEST(PostingListJoinDataSerializerTest, MoveToPostingListTooSmall) {
532 PostingListJoinDataSerializer<DocumentIdToJoinInfo<NamespaceIdFingerprint>>
533 serializer;
534
535 int size1 = 3 * serializer.GetMinPostingListSize();
536 ICING_ASSERT_OK_AND_ASSIGN(
537 PostingListUsed pl_used1,
538 PostingListUsed::CreateFromUnitializedRegion(&serializer, size1));
539 std::vector<DocumentIdToJoinInfo<NamespaceIdFingerprint>> data_arr1 = {
540 DocumentIdToJoinInfo<NamespaceIdFingerprint>(
541 /*document_id=*/0,
542 NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/2)),
543 DocumentIdToJoinInfo<NamespaceIdFingerprint>(
544 /*document_id=*/1,
545 NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/5)),
546 DocumentIdToJoinInfo<NamespaceIdFingerprint>(
547 /*document_id=*/2,
548 NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/10)),
549 DocumentIdToJoinInfo<NamespaceIdFingerprint>(
550 /*document_id=*/3,
551 NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/0)),
552 DocumentIdToJoinInfo<NamespaceIdFingerprint>(
553 /*document_id=*/4,
554 NamespaceIdFingerprint(/*namespace_id=*/0, /*fingerprint=*/1234))};
555 ASSERT_THAT(
556 serializer.PrependDataArray(&pl_used1, data_arr1.data(), data_arr1.size(),
557 /*keep_prepended=*/false),
558 IsOkAndHolds(data_arr1.size()));
559
560 int size2 = serializer.GetMinPostingListSize();
561 ICING_ASSERT_OK_AND_ASSIGN(
562 PostingListUsed pl_used2,
563 PostingListUsed::CreateFromUnitializedRegion(&serializer, size2));
564 std::vector<DocumentIdToJoinInfo<NamespaceIdFingerprint>> data_arr2 = {
565 DocumentIdToJoinInfo<NamespaceIdFingerprint>(
566 /*document_id=*/5,
567 NamespaceIdFingerprint(/*namespace_id=*/2, /*fingerprint=*/99))};
568 ASSERT_THAT(
569 serializer.PrependDataArray(&pl_used2, data_arr2.data(), data_arr2.size(),
570 /*keep_prepended=*/false),
571 IsOkAndHolds(data_arr2.size()));
572
573 EXPECT_THAT(serializer.MoveFrom(/*dst=*/&pl_used2, /*src=*/&pl_used1),
574 StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT));
575 EXPECT_THAT(
576 serializer.GetData(&pl_used1),
577 IsOkAndHolds(ElementsAreArray(data_arr1.rbegin(), data_arr1.rend())));
578 EXPECT_THAT(
579 serializer.GetData(&pl_used2),
580 IsOkAndHolds(ElementsAreArray(data_arr2.rbegin(), data_arr2.rend())));
581 }
582
TEST(PostingListJoinDataSerializerTest,PopFrontData)583 TEST(PostingListJoinDataSerializerTest, PopFrontData) {
584 PostingListJoinDataSerializer<DocumentIdToJoinInfo<NamespaceIdFingerprint>>
585 serializer;
586
587 int size = 2 * serializer.GetMinPostingListSize();
588 ICING_ASSERT_OK_AND_ASSIGN(
589 PostingListUsed pl_used,
590 PostingListUsed::CreateFromUnitializedRegion(&serializer, size));
591
592 std::vector<DocumentIdToJoinInfo<NamespaceIdFingerprint>> data_arr = {
593 DocumentIdToJoinInfo<NamespaceIdFingerprint>(
594 /*document_id=*/0,
595 NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/2)),
596 DocumentIdToJoinInfo<NamespaceIdFingerprint>(
597 /*document_id=*/1,
598 NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/5)),
599 DocumentIdToJoinInfo<NamespaceIdFingerprint>(
600 /*document_id=*/2,
601 NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/10))};
602 ASSERT_THAT(
603 serializer.PrependDataArray(&pl_used, data_arr.data(), data_arr.size(),
604 /*keep_prepended=*/false),
605 IsOkAndHolds(data_arr.size()));
606 ASSERT_THAT(
607 serializer.GetData(&pl_used),
608 IsOkAndHolds(ElementsAreArray(data_arr.rbegin(), data_arr.rend())));
609
610 // Now, pop the last data. The posting list should contain the first three
611 // data.
612 EXPECT_THAT(serializer.PopFrontData(&pl_used, /*num_data=*/1), IsOk());
613 data_arr.pop_back();
614 EXPECT_THAT(
615 serializer.GetData(&pl_used),
616 IsOkAndHolds(ElementsAreArray(data_arr.rbegin(), data_arr.rend())));
617 }
618
619 } // namespace
620
621 } // namespace lib
622 } // namespace icing
623