1 /////////////////////////////////////////////////////////////////////////////
2 // Copyright (c) 2009-2014 Alan Wright. All rights reserved.
3 // Distributable under the terms of either the Apache License (Version 2.0)
4 // or the GNU Lesser General Public License.
5 /////////////////////////////////////////////////////////////////////////////
6
7 #include "TestInc.h"
8 #include "LuceneTestFixture.h"
9 #include "TestUtils.h"
10 #include "IndexReader.h"
11 #include "MockRAMDirectory.h"
12 #include "IndexWriter.h"
13 #include "WhitespaceAnalyzer.h"
14 #include "SimpleAnalyzer.h"
15 #include "LogDocMergePolicy.h"
16 #include "Document.h"
17 #include "Field.h"
18 #include "ReadOnlySegmentReader.h"
19 #include "ReadOnlyDirectoryReader.h"
20 #include "ParallelReader.h"
21 #include "SegmentReader.h"
22 #include "_SegmentReader.h"
23 #include "Similarity.h"
24 #include "Term.h"
25 #include "MultiReader.h"
26 #include "MiscUtils.h"
27
28 using namespace Lucene;
29
30 /// Tests cloning multiple types of readers, modifying the deletedDocs and norms and verifies copy on write semantics
31 /// of the deletedDocs and norms is implemented properly
32 typedef LuceneTestFixture IndexReaderCloneTest;
33
createDocument(int32_t n,int32_t numFields)34 static DocumentPtr createDocument(int32_t n, int32_t numFields) {
35 StringStream sb;
36 DocumentPtr doc = newLucene<Document>();
37 sb << L"a" << n;
38 doc->add(newLucene<Field>(L"field1", sb.str(), Field::STORE_YES, Field::INDEX_ANALYZED));
39 doc->add(newLucene<Field>(L"fielda", sb.str(), Field::STORE_YES, Field::INDEX_NOT_ANALYZED_NO_NORMS));
40 doc->add(newLucene<Field>(L"fieldb", sb.str(), Field::STORE_YES, Field::INDEX_NO));
41 sb << L" b" << n;
42 for (int32_t i = 1; i < numFields; ++i) {
43 doc->add(newLucene<Field>(L"field" + StringUtils::toString(i + 1), sb.str(), Field::STORE_YES, Field::INDEX_ANALYZED));
44 }
45 return doc;
46 }
47
createIndex(const DirectoryPtr & dir,bool multiSegment)48 static void createIndex(const DirectoryPtr& dir, bool multiSegment) {
49 IndexWriter::unlock(dir);
50 IndexWriterPtr w = newLucene<IndexWriter>(dir, newLucene<WhitespaceAnalyzer>(), IndexWriter::MaxFieldLengthLIMITED);
51
52 w->setMergePolicy(newLucene<LogDocMergePolicy>(w));
53
54 for (int32_t i = 0; i < 100; ++i) {
55 w->addDocument(createDocument(i, 4));
56 if (multiSegment && (i % 10) == 0) {
57 w->commit();
58 }
59 }
60
61 if (!multiSegment) {
62 w->optimize();
63 }
64
65 w->close();
66
67 IndexReaderPtr r = IndexReader::open(dir, false);
68 if (multiSegment) {
69 EXPECT_TRUE(r->getSequentialSubReaders().size() > 1);
70 } else {
71 EXPECT_EQ(r->getSequentialSubReaders().size(), 1);
72 }
73 r->close();
74 }
75
isReadOnly(const IndexReaderPtr & r)76 static bool isReadOnly(const IndexReaderPtr& r) {
77 return (MiscUtils::typeOf<ReadOnlySegmentReader>(r) || MiscUtils::typeOf<ReadOnlyDirectoryReader>(r));
78 }
79
deleteWorked(int32_t doc,const IndexReaderPtr & r)80 static bool deleteWorked(int32_t doc, const IndexReaderPtr& r) {
81 bool exception = false;
82 try {
83 // trying to delete from the original reader should throw an exception
84 r->deleteDocument(doc);
85 } catch (...) {
86 exception = true;
87 }
88 return !exception;
89 }
90
91 /// 1. Get a norm from the original reader
92 /// 2. Clone the original reader
93 /// 3. Delete a document and set the norm of the cloned reader
94 /// 4. Verify the norms are not the same on each reader
95 /// 5. Verify the doc deleted is only in the cloned reader
96 /// 6. Try to delete a document in the original reader, an exception should be thrown
performDefaultTests(const IndexReaderPtr & r1)97 static void performDefaultTests(const IndexReaderPtr& r1) {
98 double norm1 = Similarity::decodeNorm(r1->norms(L"field1")[4]);
99
100 IndexReaderPtr pr1Clone = boost::dynamic_pointer_cast<IndexReader>(r1->clone());
101 pr1Clone->deleteDocument(10);
102 pr1Clone->setNorm(4, L"field1", 0.5);
103 EXPECT_TRUE(Similarity::decodeNorm(r1->norms(L"field1")[4]) == norm1);
104 EXPECT_NE(Similarity::decodeNorm(pr1Clone->norms(L"field1")[4]), norm1);
105
106 EXPECT_TRUE(!r1->isDeleted(10));
107 EXPECT_TRUE(pr1Clone->isDeleted(10));
108
109 // try to update the original reader, which should throw an exception
110 try {
111 r1->deleteDocument(11);
112 } catch (LuceneException& e) {
113 EXPECT_TRUE(check_exception(LuceneException::Null)(e));
114 }
115 pr1Clone->close();
116 }
117
modifyIndex(int32_t i,const DirectoryPtr & dir)118 static void modifyIndex(int32_t i, const DirectoryPtr& dir) {
119 switch (i) {
120 case 0: {
121 IndexWriterPtr w = newLucene<IndexWriter>(dir, newLucene<WhitespaceAnalyzer>(), IndexWriter::MaxFieldLengthLIMITED);
122 w->deleteDocuments(newLucene<Term>(L"field2", L"a11"));
123 w->deleteDocuments(newLucene<Term>(L"field2", L"b30"));
124 w->close();
125 break;
126 }
127 case 1: {
128 IndexReaderPtr reader = IndexReader::open(dir, false);
129 reader->setNorm(4, L"field1", (uint8_t)123);
130 reader->setNorm(44, L"field2", (uint8_t)222);
131 reader->setNorm(44, L"field4", (uint8_t)22);
132 reader->close();
133 break;
134 }
135 case 2: {
136 IndexWriterPtr w = newLucene<IndexWriter>(dir, newLucene<WhitespaceAnalyzer>(), IndexWriter::MaxFieldLengthLIMITED);
137 w->optimize();
138 w->close();
139 break;
140 }
141 case 3: {
142 IndexWriterPtr w = newLucene<IndexWriter>(dir, newLucene<WhitespaceAnalyzer>(), IndexWriter::MaxFieldLengthLIMITED);
143 w->addDocument(createDocument(101, 4));
144 w->optimize();
145 w->addDocument(createDocument(102, 4));
146 w->addDocument(createDocument(103, 4));
147 w->close();
148 break;
149 }
150 case 4: {
151 IndexReaderPtr reader = IndexReader::open(dir, false);
152 reader->setNorm(5, L"field1", (uint8_t)123);
153 reader->setNorm(55, L"field2", (uint8_t)222);
154 reader->close();
155 break;
156 }
157 case 5: {
158 IndexWriterPtr w = newLucene<IndexWriter>(dir, newLucene<WhitespaceAnalyzer>(), IndexWriter::MaxFieldLengthLIMITED);
159 w->addDocument(createDocument(101, 4));
160 w->close();
161 break;
162 }
163 }
164 }
165
checkDelDocsRefCountEquals(int32_t refCount,const SegmentReaderPtr & reader)166 static void checkDelDocsRefCountEquals(int32_t refCount, const SegmentReaderPtr& reader) {
167 EXPECT_EQ(refCount, reader->deletedDocsRef->refCount());
168 }
169
checkDocDeleted(const SegmentReaderPtr & reader,const SegmentReaderPtr & reader2,int32_t doc)170 static void checkDocDeleted(const SegmentReaderPtr& reader, const SegmentReaderPtr& reader2, int32_t doc) {
171 EXPECT_EQ(reader->isDeleted(doc), reader2->isDeleted(doc));
172 }
173
TEST_F(IndexReaderCloneTest,testCloneReadOnlySegmentReader)174 TEST_F(IndexReaderCloneTest, testCloneReadOnlySegmentReader) {
175 DirectoryPtr dir1 = newLucene<MockRAMDirectory>();
176 createIndex(dir1, false);
177 IndexReaderPtr reader = IndexReader::open(dir1, false);
178 IndexReaderPtr readOnlyReader = boost::dynamic_pointer_cast<IndexReader>(reader->clone(true));
179 EXPECT_TRUE(isReadOnly(readOnlyReader));
180 EXPECT_TRUE(!deleteWorked(1, readOnlyReader));
181 reader->close();
182 readOnlyReader->close();
183 dir1->close();
184 }
185
186 /// Open non-readOnly reader1, clone to non-readOnly reader2, make sure we can change reader2
TEST_F(IndexReaderCloneTest,testCloneNoChangesStillReadOnly)187 TEST_F(IndexReaderCloneTest, testCloneNoChangesStillReadOnly) {
188 DirectoryPtr dir1 = newLucene<MockRAMDirectory>();
189 createIndex(dir1, true);
190 IndexReaderPtr r1 = IndexReader::open(dir1, false);
191 IndexReaderPtr r2 = boost::dynamic_pointer_cast<IndexReader>(r1->clone(false));
192 EXPECT_TRUE(deleteWorked(1, r2));
193 r1->close();
194 r2->close();
195 dir1->close();
196 }
197
198 /// Open non-readOnly reader1, clone to non-readOnly reader2, make sure we can change reader1
TEST_F(IndexReaderCloneTest,testCloneWriteToOrig)199 TEST_F(IndexReaderCloneTest, testCloneWriteToOrig) {
200 DirectoryPtr dir1 = newLucene<MockRAMDirectory>();
201 createIndex(dir1, true);
202 IndexReaderPtr r1 = IndexReader::open(dir1, false);
203 IndexReaderPtr r2 = boost::dynamic_pointer_cast<IndexReader>(r1->clone(false));
204 EXPECT_TRUE(deleteWorked(1, r1));
205 r1->close();
206 r2->close();
207 dir1->close();
208 }
209
210 /// Open non-readOnly reader1, clone to non-readOnly reader2, make sure we can change reader2
TEST_F(IndexReaderCloneTest,testCloneWriteToClone)211 TEST_F(IndexReaderCloneTest, testCloneWriteToClone) {
212 DirectoryPtr dir1 = newLucene<MockRAMDirectory>();
213 createIndex(dir1, true);
214 IndexReaderPtr r1 = IndexReader::open(dir1, false);
215 IndexReaderPtr r2 = boost::dynamic_pointer_cast<IndexReader>(r1->clone(false));
216 EXPECT_TRUE(deleteWorked(1, r2));
217 // should fail because reader1 holds the write lock
218 EXPECT_TRUE(!deleteWorked(1, r1));
219 r2->close();
220 // should fail because we are now stale (reader1 committed changes)
221 EXPECT_TRUE(!deleteWorked(1, r1));
222 r1->close();
223
224 dir1->close();
225 }
226
227 /// Create single-segment index, open non-readOnly SegmentReader, add docs, reopen to multireader, then do delete
TEST_F(IndexReaderCloneTest,testReopenSegmentReaderToMultiReader)228 TEST_F(IndexReaderCloneTest, testReopenSegmentReaderToMultiReader) {
229 DirectoryPtr dir1 = newLucene<MockRAMDirectory>();
230 createIndex(dir1, false);
231 IndexReaderPtr reader1 = IndexReader::open(dir1, false);
232
233 modifyIndex(5, dir1);
234
235 IndexReaderPtr reader2 = reader1->reopen();
236 EXPECT_NE(reader1, reader2);
237
238 EXPECT_TRUE(deleteWorked(1, reader2));
239 reader1->close();
240 reader2->close();
241 dir1->close();
242 }
243
244 /// Open non-readOnly reader1, clone to readOnly reader2
TEST_F(IndexReaderCloneTest,testCloneWriteableToReadOnly)245 TEST_F(IndexReaderCloneTest, testCloneWriteableToReadOnly) {
246 DirectoryPtr dir1 = newLucene<MockRAMDirectory>();
247 createIndex(dir1, true);
248 IndexReaderPtr reader = IndexReader::open(dir1, false);
249 IndexReaderPtr readOnlyReader = boost::dynamic_pointer_cast<IndexReader>(reader->clone(true));
250
251 EXPECT_TRUE(isReadOnly(readOnlyReader));
252 EXPECT_TRUE(!deleteWorked(1, readOnlyReader));
253 EXPECT_TRUE(!readOnlyReader->hasChanges());
254
255 reader->close();
256 readOnlyReader->close();
257 dir1->close();
258 }
259
260 /// Open non-readOnly reader1, reopen to readOnly reader2
TEST_F(IndexReaderCloneTest,testReopenWriteableToReadOnly)261 TEST_F(IndexReaderCloneTest, testReopenWriteableToReadOnly) {
262 DirectoryPtr dir1 = newLucene<MockRAMDirectory>();
263 createIndex(dir1, true);
264 IndexReaderPtr reader = IndexReader::open(dir1, false);
265 int32_t docCount = reader->numDocs();
266 EXPECT_TRUE(deleteWorked(1, reader));
267 EXPECT_EQ(docCount - 1, reader->numDocs());
268
269 IndexReaderPtr readOnlyReader = reader->reopen(true);
270 EXPECT_TRUE(isReadOnly(readOnlyReader));
271 EXPECT_TRUE(!deleteWorked(1, readOnlyReader));
272 EXPECT_EQ(docCount - 1, readOnlyReader->numDocs());
273 reader->close();
274 readOnlyReader->close();
275 dir1->close();
276 }
277
278 /// Open readOnly reader1, clone to non-readOnly reader2
TEST_F(IndexReaderCloneTest,testCloneReadOnlyToWriteable)279 TEST_F(IndexReaderCloneTest, testCloneReadOnlyToWriteable) {
280 DirectoryPtr dir1 = newLucene<MockRAMDirectory>();
281 createIndex(dir1, true);
282 IndexReaderPtr reader1 = IndexReader::open(dir1, true);
283 IndexReaderPtr reader2 = boost::dynamic_pointer_cast<IndexReader>(reader1->clone(false));
284
285 EXPECT_TRUE(!isReadOnly(reader2));
286 EXPECT_TRUE(!deleteWorked(1, reader1));
287 // this readonly reader shouldn't yet have a write lock
288 EXPECT_TRUE(!reader2->hasChanges());
289 EXPECT_TRUE(deleteWorked(1, reader2));
290 reader1->close();
291 reader2->close();
292 dir1->close();
293 }
294
295 /// Open non-readOnly reader1 on multi-segment index, then optimize the index, then clone to readOnly reader2
TEST_F(IndexReaderCloneTest,testReadOnlyCloneAfterOptimize)296 TEST_F(IndexReaderCloneTest, testReadOnlyCloneAfterOptimize) {
297 DirectoryPtr dir1 = newLucene<MockRAMDirectory>();
298 createIndex(dir1, true);
299 IndexReaderPtr reader1 = IndexReader::open(dir1, false);
300 IndexWriterPtr w = newLucene<IndexWriter>(dir1, newLucene<SimpleAnalyzer>(), IndexWriter::MaxFieldLengthLIMITED);
301 w->optimize();
302 w->close();
303 IndexReaderPtr reader2 = boost::dynamic_pointer_cast<IndexReader>(reader1->clone(true));
304 EXPECT_TRUE(isReadOnly(reader2));
305 reader1->close();
306 reader2->close();
307 dir1->close();
308 }
309
TEST_F(IndexReaderCloneTest,testCloneReadOnlyDirectoryReader)310 TEST_F(IndexReaderCloneTest, testCloneReadOnlyDirectoryReader) {
311 DirectoryPtr dir1 = newLucene<MockRAMDirectory>();
312 createIndex(dir1, true);
313 IndexReaderPtr reader = IndexReader::open(dir1, false);
314 IndexReaderPtr readOnlyReader = boost::dynamic_pointer_cast<IndexReader>(reader->clone(true));
315 EXPECT_TRUE(isReadOnly(readOnlyReader));
316 reader->close();
317 readOnlyReader->close();
318 dir1->close();
319 }
320
TEST_F(IndexReaderCloneTest,testParallelReader)321 TEST_F(IndexReaderCloneTest, testParallelReader) {
322 DirectoryPtr dir1 = newLucene<MockRAMDirectory>();
323 createIndex(dir1, true);
324 DirectoryPtr dir2 = newLucene<MockRAMDirectory>();
325 createIndex(dir2, true);
326
327 IndexReaderPtr r1 = IndexReader::open(dir1, false);
328 IndexReaderPtr r2 = IndexReader::open(dir2, false);
329
330 ParallelReaderPtr pr1 = newLucene<ParallelReader>();
331 pr1->add(r1);
332 pr1->add(r2);
333
334 performDefaultTests(pr1);
335 pr1->close();
336 dir1->close();
337 dir2->close();
338 }
339
TEST_F(IndexReaderCloneTest,testMixedReaders)340 TEST_F(IndexReaderCloneTest, testMixedReaders) {
341 DirectoryPtr dir1 = newLucene<MockRAMDirectory>();
342 createIndex(dir1, true);
343 DirectoryPtr dir2 = newLucene<MockRAMDirectory>();
344 createIndex(dir2, true);
345
346 IndexReaderPtr r1 = IndexReader::open(dir1, false);
347 IndexReaderPtr r2 = IndexReader::open(dir2, false);
348
349 Collection<IndexReaderPtr> multiReaders = newCollection<IndexReaderPtr>(r1, r2);
350 MultiReaderPtr multiReader = newLucene<MultiReader>(multiReaders);
351 performDefaultTests(multiReader);
352 multiReader->close();
353 dir1->close();
354 dir2->close();
355 }
356
TEST_F(IndexReaderCloneTest,testSegmentReaderUndeleteall)357 TEST_F(IndexReaderCloneTest, testSegmentReaderUndeleteall) {
358 DirectoryPtr dir1 = newLucene<MockRAMDirectory>();
359 createIndex(dir1, false);
360 SegmentReaderPtr origSegmentReader = SegmentReader::getOnlySegmentReader(dir1);
361 origSegmentReader->deleteDocument(10);
362 checkDelDocsRefCountEquals(1, origSegmentReader);
363 origSegmentReader->undeleteAll();
364 EXPECT_TRUE(!origSegmentReader->deletedDocsRef);
365 origSegmentReader->close();
366 // need to test norms?
367 dir1->close();
368 }
369
TEST_F(IndexReaderCloneTest,testSegmentReaderCloseReferencing)370 TEST_F(IndexReaderCloneTest, testSegmentReaderCloseReferencing) {
371 DirectoryPtr dir1 = newLucene<MockRAMDirectory>();
372 createIndex(dir1, false);
373 SegmentReaderPtr origSegmentReader = SegmentReader::getOnlySegmentReader(dir1);
374 origSegmentReader->deleteDocument(1);
375 origSegmentReader->setNorm(4, L"field1", 0.5);
376
377 SegmentReaderPtr clonedSegmentReader = boost::dynamic_pointer_cast<SegmentReader>(origSegmentReader->clone());
378 checkDelDocsRefCountEquals(2, origSegmentReader);
379 origSegmentReader->close();
380 checkDelDocsRefCountEquals(1, origSegmentReader);
381 // check the norm refs
382 NormPtr norm = clonedSegmentReader->_norms.get(L"field1");
383 EXPECT_EQ(1, norm->bytesRef()->refCount());
384 clonedSegmentReader->close();
385 dir1->close();
386 }
387
TEST_F(IndexReaderCloneTest,testSegmentReaderDelDocsReferenceCounting)388 TEST_F(IndexReaderCloneTest, testSegmentReaderDelDocsReferenceCounting) {
389 DirectoryPtr dir1 = newLucene<MockRAMDirectory>();
390 createIndex(dir1, false);
391 IndexReaderPtr origReader = IndexReader::open(dir1, false);
392 SegmentReaderPtr origSegmentReader = SegmentReader::getOnlySegmentReader(origReader);
393 // deletedDocsRef should be null because nothing has updated yet
394 EXPECT_TRUE(!origSegmentReader->deletedDocsRef);
395
396 // we deleted a document, so there is now a deletedDocs bitvector and a reference to it
397 origReader->deleteDocument(1);
398 checkDelDocsRefCountEquals(1, origSegmentReader);
399
400 // the cloned segmentreader should have 2 references, 1 to itself, and 1 to the original segmentreader
401 IndexReaderPtr clonedReader = boost::dynamic_pointer_cast<IndexReader>(origReader->clone());
402 SegmentReaderPtr clonedSegmentReader = SegmentReader::getOnlySegmentReader(clonedReader);
403 checkDelDocsRefCountEquals(2, origSegmentReader);
404 // deleting a document creates a new deletedDocs bitvector, the refs goes to 1
405 clonedReader->deleteDocument(2);
406 checkDelDocsRefCountEquals(1, origSegmentReader);
407 checkDelDocsRefCountEquals(1, clonedSegmentReader);
408
409 // make sure the deletedocs objects are different (copy on write)
410 EXPECT_NE(origSegmentReader->deletedDocs, clonedSegmentReader->deletedDocs);
411
412 checkDocDeleted(origSegmentReader, clonedSegmentReader, 1);
413 EXPECT_TRUE(!origSegmentReader->isDeleted(2)); // doc 2 should not be deleted in original segmentreader
414 EXPECT_TRUE(clonedSegmentReader->isDeleted(2)); // doc 2 should be deleted in cloned segmentreader
415
416 try {
417 origReader->deleteDocument(4);
418 } catch (LockObtainFailedException& e) {
419 EXPECT_TRUE(check_exception(LuceneException::LockObtainFailed)(e));
420 }
421
422 origReader->close();
423 // try closing the original segment reader to see if it affects the clonedSegmentReader
424 clonedReader->deleteDocument(3);
425 clonedReader->flush();
426 checkDelDocsRefCountEquals(1, clonedSegmentReader);
427
428 // test a reopened reader
429 IndexReaderPtr reopenedReader = clonedReader->reopen();
430 IndexReaderPtr cloneReader2 = boost::dynamic_pointer_cast<IndexReader>(reopenedReader->clone());
431 SegmentReaderPtr cloneSegmentReader2 = SegmentReader::getOnlySegmentReader(cloneReader2);
432 checkDelDocsRefCountEquals(2, cloneSegmentReader2);
433 clonedReader->close();
434 reopenedReader->close();
435 cloneReader2->close();
436
437 dir1->close();
438 }
439
TEST_F(IndexReaderCloneTest,testCloneWithDeletes)440 TEST_F(IndexReaderCloneTest, testCloneWithDeletes) {
441 DirectoryPtr dir1 = newLucene<MockRAMDirectory>();
442 createIndex(dir1, false);
443 IndexReaderPtr origReader = IndexReader::open(dir1, false);
444 origReader->deleteDocument(1);
445
446 IndexReaderPtr clonedReader = boost::dynamic_pointer_cast<IndexReader>(origReader->clone());
447 origReader->close();
448 clonedReader->close();
449
450 IndexReaderPtr r = IndexReader::open(dir1, false);
451 EXPECT_TRUE(r->isDeleted(1));
452 r->close();
453 dir1->close();
454 }
455
TEST_F(IndexReaderCloneTest,testCloneWithSetNorm)456 TEST_F(IndexReaderCloneTest, testCloneWithSetNorm) {
457 DirectoryPtr dir1 = newLucene<MockRAMDirectory>();
458 createIndex(dir1, false);
459 IndexReaderPtr orig = IndexReader::open(dir1, false);
460 orig->setNorm(1, L"field1", 17.0);
461 uint8_t encoded = Similarity::encodeNorm(17.0);
462 EXPECT_EQ(encoded, orig->norms(L"field1")[1]);
463
464 // the cloned segmentreader should have 2 references, 1 to itself, and 1 to the original segmentreader
465 IndexReaderPtr clonedReader = boost::dynamic_pointer_cast<IndexReader>(orig->clone());
466 orig->close();
467 clonedReader->close();
468
469 IndexReaderPtr r = IndexReader::open(dir1, false);
470 EXPECT_EQ(encoded, r->norms(L"field1")[1]);
471 r->close();
472 dir1->close();
473 }
474
TEST_F(IndexReaderCloneTest,testCloneSubreaders)475 TEST_F(IndexReaderCloneTest, testCloneSubreaders) {
476 DirectoryPtr dir1 = newLucene<MockRAMDirectory>();
477 createIndex(dir1, true);
478
479 IndexReaderPtr reader = IndexReader::open(dir1, false);
480 reader->deleteDocument(1); // acquire write lock
481 Collection<IndexReaderPtr> subs = reader->getSequentialSubReaders();
482 EXPECT_TRUE(subs.size() > 1);
483
484 Collection<IndexReaderPtr> clones = Collection<IndexReaderPtr>::newInstance(subs.size());
485 for (int32_t x = 0; x < subs.size(); ++x) {
486 clones[x] = boost::dynamic_pointer_cast<IndexReader>(subs[x]->clone());
487 }
488 reader->close();
489 for (int32_t x = 0; x < subs.size(); ++x) {
490 clones[x]->close();
491 }
492 dir1->close();
493 }
494
TEST_F(IndexReaderCloneTest,testIncDecRef)495 TEST_F(IndexReaderCloneTest, testIncDecRef) {
496 DirectoryPtr dir1 = newLucene<MockRAMDirectory>();
497 createIndex(dir1, false);
498 IndexReaderPtr r1 = IndexReader::open(dir1, false);
499 r1->incRef();
500 IndexReaderPtr r2 = boost::dynamic_pointer_cast<IndexReader>(r1->clone(false));
501 r1->deleteDocument(5);
502 r1->decRef();
503
504 r1->incRef();
505
506 r2->close();
507 r1->decRef();
508 r1->close();
509 dir1->close();
510 }
511
TEST_F(IndexReaderCloneTest,testCloseStoredFields)512 TEST_F(IndexReaderCloneTest, testCloseStoredFields) {
513 DirectoryPtr dir = newLucene<MockRAMDirectory>();
514 IndexWriterPtr w = newLucene<IndexWriter>(dir, newLucene<SimpleAnalyzer>(), IndexWriter::MaxFieldLengthUNLIMITED);
515 w->setUseCompoundFile(false);
516 DocumentPtr doc = newLucene<Document>();
517 doc->add(newLucene<Field>(L"field", L"yes it's stored", Field::STORE_YES, Field::INDEX_ANALYZED));
518 w->addDocument(doc);
519 w->close();
520 IndexReaderPtr r1 = IndexReader::open(dir, false);
521 IndexReaderPtr r2 = boost::dynamic_pointer_cast<IndexReader>(r1->clone(false));
522 r1->close();
523 r2->close();
524 dir->close();
525 }
526