~slub.team/goobi-indexserver/3.x

« back to all changes in this revision

Viewing changes to lucene/src/test/org/apache/lucene/index/TestSnapshotDeletionPolicy.java

  • Committer: Sebastian Meyer
  • Date: 2012-08-03 09:12:40 UTC
  • Revision ID: sebastian.meyer@slub-dresden.de-20120803091240-x6861b0vabq1xror
Remove Lucene and Solr source code and add patches instead
Fix Bug #985487: Auto-suggestion for the search interface

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
package org.apache.lucene.index;
2
 
 
3
 
/**
4
 
 * Licensed to the Apache Software Foundation (ASF) under one or more
5
 
 * contributor license agreements.  See the NOTICE file distributed with
6
 
 * this work for additional information regarding copyright ownership.
7
 
 * The ASF licenses this file to You under the Apache License, Version 2.0
8
 
 * (the "License"); you may not use this file except in compliance with
9
 
 * the License.  You may obtain a copy of the License at
10
 
 *
11
 
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 
 *
13
 
 * Unless required by applicable law or agreed to in writing, software
14
 
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 
 * See the License for the specific language governing permissions and
17
 
 * limitations under the License.
18
 
 */
19
 
 
20
 
import java.util.Collection;
21
 
import java.util.Map;
22
 
import java.util.Random;
23
 
import java.io.IOException;
24
 
 
25
 
import org.apache.lucene.document.Document;
26
 
import org.apache.lucene.document.Field;
27
 
import org.apache.lucene.store.Directory;
28
 
import org.apache.lucene.store.IndexInput;
29
 
import org.apache.lucene.analysis.KeywordAnalyzer;
30
 
import org.apache.lucene.analysis.MockAnalyzer;
31
 
import org.apache.lucene.analysis.standard.StandardAnalyzer;
32
 
import org.apache.lucene.index.IndexCommit;
33
 
import org.apache.lucene.index.IndexWriterConfig;
34
 
import org.apache.lucene.index.KeepOnlyLastCommitDeletionPolicy;
35
 
import org.apache.lucene.index.IndexWriter;
36
 
import org.apache.lucene.index.SnapshotDeletionPolicy;
37
 
import org.apache.lucene.util.LuceneTestCase;
38
 
import org.apache.lucene.util.ThreadInterruptedException;
39
 
import org.junit.Test;
40
 
 
41
 
//
42
 
// This was developed for Lucene In Action,
43
 
// http://lucenebook.com
44
 
//
45
 
 
46
 
public class TestSnapshotDeletionPolicy extends LuceneTestCase {
47
 
  public static final String INDEX_PATH = "test.snapshots";
48
 
  
49
 
  protected IndexWriterConfig getConfig(Random random, IndexDeletionPolicy dp) {
50
 
    IndexWriterConfig conf = newIndexWriterConfig( TEST_VERSION_CURRENT, new MockAnalyzer(random));
51
 
    if (dp != null) {
52
 
      conf.setIndexDeletionPolicy(dp);
53
 
    }
54
 
    return conf;
55
 
  }
56
 
 
57
 
  protected void checkSnapshotExists(Directory dir, IndexCommit c) throws Exception {
58
 
    String segFileName = c.getSegmentsFileName();
59
 
    assertTrue("segments file not found in directory: " + segFileName, dir.fileExists(segFileName));
60
 
  }
61
 
 
62
 
  protected void checkMaxDoc(IndexCommit commit, int expectedMaxDoc) throws Exception {
63
 
    IndexReader reader = IndexReader.open(commit, true);
64
 
    try {
65
 
      assertEquals(expectedMaxDoc, reader.maxDoc());
66
 
    } finally {
67
 
      reader.close();
68
 
    }
69
 
  }
70
 
 
71
 
  protected void prepareIndexAndSnapshots(SnapshotDeletionPolicy sdp,
72
 
      IndexWriter writer, int numSnapshots, String snapshotPrefix)
73
 
      throws RuntimeException, IOException {
74
 
    for (int i = 0; i < numSnapshots; i++) {
75
 
      // create dummy document to trigger commit.
76
 
      writer.addDocument(new Document());
77
 
      writer.commit();
78
 
      sdp.snapshot(snapshotPrefix + i);
79
 
    }
80
 
  }
81
 
 
82
 
  protected SnapshotDeletionPolicy getDeletionPolicy() throws IOException {
83
 
    return getDeletionPolicy(null);
84
 
  }
85
 
 
86
 
  protected SnapshotDeletionPolicy getDeletionPolicy(Map<String, String> snapshots) throws IOException {
87
 
    return new SnapshotDeletionPolicy(new KeepOnlyLastCommitDeletionPolicy(), snapshots);
88
 
  }
89
 
 
90
 
  protected void assertSnapshotExists(Directory dir, SnapshotDeletionPolicy sdp, int numSnapshots) throws Exception {
91
 
    for (int i = 0; i < numSnapshots; i++) {
92
 
      IndexCommit snapshot = sdp.getSnapshot("snapshot" + i);
93
 
      checkMaxDoc(snapshot, i + 1);
94
 
      checkSnapshotExists(dir, snapshot);
95
 
    }
96
 
  }
97
 
  
98
 
  @Test
99
 
  public void testSnapshotDeletionPolicy() throws Exception {
100
 
    Directory fsDir = newDirectory();
101
 
    runTest(random, fsDir);
102
 
    fsDir.close();
103
 
  }
104
 
 
105
 
  private void runTest(Random random, Directory dir) throws Exception {
106
 
    // Run for ~1 seconds
107
 
    final long stopTime = System.currentTimeMillis() + 1000;
108
 
 
109
 
    SnapshotDeletionPolicy dp = getDeletionPolicy();
110
 
    final IndexWriter writer = new IndexWriter(dir, newIndexWriterConfig(
111
 
        TEST_VERSION_CURRENT, new MockAnalyzer(random)).setIndexDeletionPolicy(dp)
112
 
        .setMaxBufferedDocs(2));
113
 
    writer.commit();
114
 
    
115
 
    final Thread t = new Thread() {
116
 
        @Override
117
 
        public void run() {
118
 
          Document doc = new Document();
119
 
          doc.add(newField("content", "aaa", Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS_OFFSETS));
120
 
          do {
121
 
            for(int i=0;i<27;i++) {
122
 
              try {
123
 
                writer.addDocument(doc);
124
 
              } catch (Throwable t) {
125
 
                t.printStackTrace(System.out);
126
 
                fail("addDocument failed");
127
 
              }
128
 
              if (i%2 == 0) {
129
 
                try {
130
 
                  writer.commit();
131
 
                } catch (Exception e) {
132
 
                  throw new RuntimeException(e);
133
 
                }
134
 
              }
135
 
            }
136
 
            try {
137
 
              Thread.sleep(1);
138
 
            } catch (InterruptedException ie) {
139
 
              throw new ThreadInterruptedException(ie);
140
 
            }
141
 
          } while(System.currentTimeMillis() < stopTime);
142
 
        }
143
 
      };
144
 
 
145
 
    t.start();
146
 
 
147
 
    // While the above indexing thread is running, take many
148
 
    // backups:
149
 
    do {
150
 
      backupIndex(dir, dp);
151
 
      Thread.sleep(20);
152
 
    } while(t.isAlive());
153
 
 
154
 
    t.join();
155
 
 
156
 
    // Add one more document to force writer to commit a
157
 
    // final segment, so deletion policy has a chance to
158
 
    // delete again:
159
 
    Document doc = new Document();
160
 
    doc.add(newField("content", "aaa", Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS_OFFSETS));
161
 
    writer.addDocument(doc);
162
 
 
163
 
    // Make sure we don't have any leftover files in the
164
 
    // directory:
165
 
    writer.close();
166
 
    TestIndexWriter.assertNoUnreferencedFiles(dir, "some files were not deleted but should have been");
167
 
  }
168
 
 
169
 
  /**
170
 
   * Example showing how to use the SnapshotDeletionPolicy to take a backup.
171
 
   * This method does not really do a backup; instead, it reads every byte of
172
 
   * every file just to test that the files indeed exist and are readable even
173
 
   * while the index is changing.
174
 
   */
175
 
  public void backupIndex(Directory dir, SnapshotDeletionPolicy dp) throws Exception {
176
 
    // To backup an index we first take a snapshot:
177
 
    try {
178
 
      copyFiles(dir,  dp.snapshot("id"));
179
 
    } finally {
180
 
      // Make sure to release the snapshot, otherwise these
181
 
      // files will never be deleted during this IndexWriter
182
 
      // session:
183
 
      dp.release("id");
184
 
    }
185
 
  }
186
 
 
187
 
  private void copyFiles(Directory dir, IndexCommit cp) throws Exception {
188
 
 
189
 
    // While we hold the snapshot, and nomatter how long
190
 
    // we take to do the backup, the IndexWriter will
191
 
    // never delete the files in the snapshot:
192
 
    Collection<String> files = cp.getFileNames();
193
 
    for (final String fileName : files) { 
194
 
      // NOTE: in a real backup you would not use
195
 
      // readFile; you would need to use something else
196
 
      // that copies the file to a backup location.  This
197
 
      // could even be a spawned shell process (eg "tar",
198
 
      // "zip") that takes the list of files and builds a
199
 
      // backup.
200
 
      readFile(dir, fileName);
201
 
    }
202
 
  }
203
 
 
204
 
  byte[] buffer = new byte[4096];
205
 
 
206
 
  private void readFile(Directory dir, String name) throws Exception {
207
 
    IndexInput input = dir.openInput(name);
208
 
    try {
209
 
      long size = dir.fileLength(name);
210
 
      long bytesLeft = size;
211
 
      while (bytesLeft > 0) {
212
 
        final int numToRead;
213
 
        if (bytesLeft < buffer.length)
214
 
          numToRead = (int) bytesLeft;
215
 
        else
216
 
          numToRead = buffer.length;
217
 
        input.readBytes(buffer, 0, numToRead, false);
218
 
        bytesLeft -= numToRead;
219
 
      }
220
 
      // Don't do this in your real backups!  This is just
221
 
      // to force a backup to take a somewhat long time, to
222
 
      // make sure we are exercising the fact that the
223
 
      // IndexWriter should not delete this file even when I
224
 
      // take my time reading it.
225
 
      Thread.sleep(1);
226
 
    } finally {
227
 
      input.close();
228
 
    }
229
 
  }
230
 
 
231
 
  
232
 
  @Test
233
 
  public void testBasicSnapshots() throws Exception {
234
 
    int numSnapshots = 3;
235
 
    SnapshotDeletionPolicy sdp = getDeletionPolicy();
236
 
    
237
 
    // Create 3 snapshots: snapshot0, snapshot1, snapshot2
238
 
    Directory dir = newDirectory();
239
 
    IndexWriter writer = new IndexWriter(dir, getConfig(random, sdp));
240
 
    prepareIndexAndSnapshots(sdp, writer, numSnapshots, "snapshot");
241
 
    writer.close();
242
 
    
243
 
    assertSnapshotExists(dir, sdp, numSnapshots);
244
 
 
245
 
    // open a reader on a snapshot - should succeed.
246
 
    IndexReader.open(sdp.getSnapshot("snapshot0"), true).close();
247
 
 
248
 
    // open a new IndexWriter w/ no snapshots to keep and assert that all snapshots are gone.
249
 
    sdp = getDeletionPolicy();
250
 
    writer = new IndexWriter(dir, getConfig(random, sdp));
251
 
    writer.deleteUnusedFiles();
252
 
    writer.close();
253
 
    assertEquals("no snapshots should exist", 1, IndexReader.listCommits(dir).size());
254
 
    
255
 
    for (int i = 0; i < numSnapshots; i++) {
256
 
      try {
257
 
        sdp.getSnapshot("snapshot" + i);
258
 
        fail("snapshot shouldn't have existed, but did: snapshot" + i);
259
 
      } catch (IllegalStateException e) {
260
 
        // expected - snapshot should not exist
261
 
      }
262
 
    }
263
 
    dir.close();
264
 
  }
265
 
 
266
 
  @Test
267
 
  public void testMultiThreadedSnapshotting() throws Exception {
268
 
    Directory dir = newDirectory();
269
 
    final SnapshotDeletionPolicy sdp = getDeletionPolicy();
270
 
    final IndexWriter writer = new IndexWriter(dir, getConfig(random, sdp));
271
 
 
272
 
    Thread[] threads = new Thread[10];
273
 
    for (int i = 0; i < threads.length; i++) {
274
 
      threads[i] = new Thread() {
275
 
        @Override
276
 
        public void run() {
277
 
          try {
278
 
            writer.addDocument(new Document());
279
 
            writer.commit();
280
 
            sdp.snapshot(getName());
281
 
          } catch (Exception e) {
282
 
            throw new RuntimeException(e);
283
 
          }
284
 
        }
285
 
      };
286
 
      threads[i].setName("t" + i);
287
 
    }
288
 
    
289
 
    for (Thread t : threads) {
290
 
      t.start();
291
 
    }
292
 
    
293
 
    for (Thread t : threads) {
294
 
      t.join();
295
 
    }
296
 
 
297
 
    // Do one last commit, so that after we release all snapshots, we stay w/ one commit
298
 
    writer.addDocument(new Document());
299
 
    writer.commit();
300
 
    
301
 
    for (Thread t : threads) {
302
 
      sdp.release(t.getName());
303
 
      writer.deleteUnusedFiles();
304
 
    }
305
 
    assertEquals(1, IndexReader.listCommits(dir).size());
306
 
    writer.close();
307
 
    dir.close();
308
 
  }
309
 
 
310
 
  @Test
311
 
  public void testRollbackToOldSnapshot() throws Exception {
312
 
    int numSnapshots = 2;
313
 
    Directory dir = newDirectory();
314
 
    SnapshotDeletionPolicy sdp = getDeletionPolicy();
315
 
    IndexWriter writer = new IndexWriter(dir, getConfig(random, sdp));
316
 
    prepareIndexAndSnapshots(sdp, writer, numSnapshots, "snapshot");
317
 
    writer.close();
318
 
 
319
 
    // now open the writer on "snapshot0" - make sure it succeeds
320
 
    writer = new IndexWriter(dir, getConfig(random, sdp).setIndexCommit(sdp.getSnapshot("snapshot0")));
321
 
    // this does the actual rollback
322
 
    writer.commit();
323
 
    writer.deleteUnusedFiles();
324
 
    assertSnapshotExists(dir, sdp, numSnapshots - 1);
325
 
    writer.close();
326
 
    
327
 
    // but 'snapshot1' files will still exist (need to release snapshot before they can be deleted).
328
 
    String segFileName = sdp.getSnapshot("snapshot1").getSegmentsFileName();
329
 
    assertTrue("snapshot files should exist in the directory: " + segFileName, dir.fileExists(segFileName));
330
 
    dir.close();
331
 
  }
332
 
 
333
 
  @Test
334
 
  public void testReleaseSnapshot() throws Exception {
335
 
    Directory dir = newDirectory();
336
 
    SnapshotDeletionPolicy sdp = getDeletionPolicy();
337
 
    IndexWriter writer = new IndexWriter(dir, getConfig(random, sdp));
338
 
    prepareIndexAndSnapshots(sdp, writer, 1, "snapshot");
339
 
    
340
 
    // Create another commit - we must do that, because otherwise the "snapshot"
341
 
    // files will still remain in the index, since it's the last commit.
342
 
    writer.addDocument(new Document());
343
 
    writer.commit();
344
 
    
345
 
    // Release
346
 
    String snapId = "snapshot0";
347
 
    String segFileName = sdp.getSnapshot(snapId).getSegmentsFileName();
348
 
    sdp.release(snapId);
349
 
    try {
350
 
      sdp.getSnapshot(snapId);
351
 
      fail("should not have succeeded to get an unsnapshotted id");
352
 
    } catch (IllegalStateException e) {
353
 
      // expected
354
 
    }
355
 
    assertNull(sdp.getSnapshots().get(snapId));
356
 
    writer.deleteUnusedFiles();
357
 
    writer.close();
358
 
    assertFalse("segments file should not be found in dirctory: " + segFileName, dir.fileExists(segFileName));
359
 
    dir.close();
360
 
  }
361
 
 
362
 
  @Test
363
 
  public void testExistingSnapshots() throws Exception {
364
 
    // Tests the ability to construct a SDP from existing snapshots, and
365
 
    // asserts that those snapshots/commit points are protected.
366
 
    int numSnapshots = 3;
367
 
    Directory dir = newDirectory();
368
 
    SnapshotDeletionPolicy sdp = getDeletionPolicy();
369
 
    IndexWriter writer = new IndexWriter(dir, getConfig(random, sdp));
370
 
    prepareIndexAndSnapshots(sdp, writer, numSnapshots, "snapshot");
371
 
    writer.close();
372
 
 
373
 
    // Make a new policy and initialize with snapshots.
374
 
    sdp = getDeletionPolicy(sdp.getSnapshots());
375
 
    writer = new IndexWriter(dir, getConfig(random, sdp));
376
 
    // attempt to delete unused files - the snapshotted files should not be deleted
377
 
    writer.deleteUnusedFiles();
378
 
    writer.close();
379
 
    assertSnapshotExists(dir, sdp, numSnapshots);
380
 
    dir.close();
381
 
  }
382
 
 
383
 
  @Test
384
 
  public void testSnapshotLastCommitTwice() throws Exception {
385
 
    Directory dir = newDirectory();
386
 
    SnapshotDeletionPolicy sdp = getDeletionPolicy();
387
 
    IndexWriter writer = new IndexWriter(dir, getConfig(random, sdp));
388
 
    writer.addDocument(new Document());
389
 
    writer.commit();
390
 
    
391
 
    String s1 = "s1";
392
 
    String s2 = "s2";
393
 
    IndexCommit ic1 = sdp.snapshot(s1);
394
 
    IndexCommit ic2 = sdp.snapshot(s2);
395
 
    assertTrue(ic1 == ic2); // should be the same instance
396
 
    
397
 
    // create another commit
398
 
    writer.addDocument(new Document());
399
 
    writer.commit();
400
 
    
401
 
    // release "s1" should not delete "s2"
402
 
    sdp.release(s1);
403
 
    writer.deleteUnusedFiles();
404
 
    checkSnapshotExists(dir, ic2);
405
 
    
406
 
    writer.close();
407
 
    dir.close();
408
 
  }
409
 
  
410
 
  @Test
411
 
  public void testMissingCommits() throws Exception {
412
 
    // Tests the behavior of SDP when commits that are given at ctor are missing
413
 
    // on onInit().
414
 
    Directory dir = newDirectory();
415
 
    SnapshotDeletionPolicy sdp = getDeletionPolicy();
416
 
    IndexWriter writer = new IndexWriter(dir, getConfig(random, sdp));
417
 
    writer.addDocument(new Document());
418
 
    writer.commit();
419
 
    IndexCommit ic = sdp.snapshot("s1");
420
 
 
421
 
    // create another commit, not snapshotted.
422
 
    writer.addDocument(new Document());
423
 
    writer.close();
424
 
 
425
 
    // open a new writer w/ KeepOnlyLastCommit policy, so it will delete "s1"
426
 
    // commit.
427
 
    new IndexWriter(dir, getConfig(random, null)).close();
428
 
    
429
 
    assertFalse("snapshotted commit should not exist", dir.fileExists(ic.getSegmentsFileName()));
430
 
    
431
 
    // Now reinit SDP from the commits in the index - the snapshot id should not
432
 
    // exist anymore.
433
 
    sdp = getDeletionPolicy(sdp.getSnapshots());
434
 
    new IndexWriter(dir, getConfig(random, sdp)).close();
435
 
    
436
 
    try {
437
 
      sdp.getSnapshot("s1");
438
 
      fail("snapshot s1 should not exist");
439
 
    } catch (IllegalStateException e) {
440
 
      // expected.
441
 
    }
442
 
    dir.close();
443
 
  }
444
 
 
445
 
}