LUCENE-1184: allow SnapshotDeletionPolicy to be re-used across close/open of IndexWriter

git-svn-id: https://svn.apache.org/repos/asf/lucene/java/trunk@631223 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Michael McCandless 2008-02-26 14:23:45 +00:00
parent 6302172390
commit d7d1d680f2
4 changed files with 82 additions and 31 deletions

View File

@ -101,6 +101,10 @@ New features
huge index might not stop within the specified time. huge index might not stop within the specified time.
(Sean Timm via Doron Cohen) (Sean Timm via Doron Cohen)
8. LUCENE-1184: Allow SnapshotDeletionPolicy to be re-used across
close/re-open of IndexWriter while still protecting an open
snapshot (Tim Brennan via Mike McCandless)
Optimizations Optimizations
1. LUCENE-705: When building a compound file, use 1. LUCENE-705: When building a compound file, use

View File

@ -187,7 +187,7 @@ final class IndexFileDeleter {
sis = null; sis = null;
} }
if (sis != null) { if (sis != null) {
CommitPoint commitPoint = new CommitPoint(sis); CommitPoint commitPoint = new CommitPoint(commitsToDelete, directory, sis);
if (sis.getGeneration() == segmentInfos.getGeneration()) { if (sis.getGeneration() == segmentInfos.getGeneration()) {
currentCommitPoint = commitPoint; currentCommitPoint = commitPoint;
} }
@ -215,7 +215,7 @@ final class IndexFileDeleter {
} }
if (infoStream != null) if (infoStream != null)
message("forced open of current segments file " + segmentInfos.getCurrentSegmentFileName()); message("forced open of current segments file " + segmentInfos.getCurrentSegmentFileName());
currentCommitPoint = new CommitPoint(sis); currentCommitPoint = new CommitPoint(commitsToDelete, directory, sis);
commits.add(currentCommitPoint); commits.add(currentCommitPoint);
incRef(sis, true); incRef(sis, true);
} }
@ -392,7 +392,7 @@ final class IndexFileDeleter {
if (isCommit) { if (isCommit) {
// Append to our commits list: // Append to our commits list:
commits.add(new CommitPoint(segmentInfos)); commits.add(new CommitPoint(commitsToDelete, directory, segmentInfos));
// Tell policy so it can remove commits: // Tell policy so it can remove commits:
policy.onCommit(commits); policy.onCommit(commits);
@ -569,14 +569,18 @@ final class IndexFileDeleter {
* equals. * equals.
*/ */
final private class CommitPoint implements Comparable, IndexCommitPoint { final private static class CommitPoint implements Comparable, IndexCommitPoint {
long gen; long gen;
List files; List files;
String segmentsFileName; String segmentsFileName;
boolean deleted; boolean deleted;
Directory directory;
Collection commitsToDelete;
public CommitPoint(SegmentInfos segmentInfos) throws IOException { public CommitPoint(Collection commitsToDelete, Directory directory, SegmentInfos segmentInfos) throws IOException {
this.directory = directory;
this.commitsToDelete = commitsToDelete;
segmentsFileName = segmentInfos.getCurrentSegmentFileName(); segmentsFileName = segmentInfos.getCurrentSegmentFileName();
int size = segmentInfos.size(); int size = segmentInfos.size();
files = new ArrayList(size); files = new ArrayList(size);

View File

@ -31,13 +31,17 @@ import java.io.IOException;
* we wrap another arbitrary {@link IndexDeletionPolicy}, this * we wrap another arbitrary {@link IndexDeletionPolicy}, this
* gives you the freedom to continue using whatever {@link * gives you the freedom to continue using whatever {@link
* IndexDeletionPolicy} you would normally want to use with your * IndexDeletionPolicy} you would normally want to use with your
* index. */ * index. Note that you can re-use a single instance of
* SnapshotDeletionPolicy across multiple writers as long
* as they are against the same index Directory. Any
* snapshot held when a writer is closed will "survive"
* when the next writer is opened. */
public class SnapshotDeletionPolicy implements IndexDeletionPolicy { public class SnapshotDeletionPolicy implements IndexDeletionPolicy {
private IndexCommitPoint lastCommit; private IndexCommitPoint lastCommit;
private IndexDeletionPolicy primary; private IndexDeletionPolicy primary;
private IndexCommitPoint snapshot; private String snapshot;
public SnapshotDeletionPolicy(IndexDeletionPolicy primary) { public SnapshotDeletionPolicy(IndexDeletionPolicy primary) {
this.primary = primary; this.primary = primary;
@ -64,10 +68,10 @@ public class SnapshotDeletionPolicy implements IndexDeletionPolicy {
* you release the snapshot. */ * you release the snapshot. */
public synchronized IndexCommitPoint snapshot() { public synchronized IndexCommitPoint snapshot() {
if (snapshot == null) if (snapshot == null)
snapshot = lastCommit; snapshot = lastCommit.getSegmentsFileName();
else else
throw new IllegalStateException("snapshot is already set; please call release() first"); throw new IllegalStateException("snapshot is already set; please call release() first");
return snapshot; return lastCommit;
} }
/** Release the currently held snapshot. */ /** Release the currently held snapshot. */
@ -93,7 +97,7 @@ public class SnapshotDeletionPolicy implements IndexDeletionPolicy {
synchronized(SnapshotDeletionPolicy.this) { synchronized(SnapshotDeletionPolicy.this) {
// Suppress the delete request if this commit point is // Suppress the delete request if this commit point is
// our current snapshot. // our current snapshot.
if (snapshot != cp) if (snapshot == null || !snapshot.equals(getSegmentsFileName()))
cp.delete(); cp.delete();
} }
} }

View File

@ -63,6 +63,44 @@ public class TestSnapshotDeletionPolicy extends LuceneTestCase
runTest(dir2); runTest(dir2);
} }
public void testReuseAcrossWriters() throws IOException {
Directory dir = new MockRAMDirectory();
SnapshotDeletionPolicy dp = new SnapshotDeletionPolicy(new KeepOnlyLastCommitDeletionPolicy());
IndexWriter writer = new IndexWriter(dir, true, new StandardAnalyzer(), dp,
IndexWriter.MaxFieldLength.LIMITED);
// Force frequent commits
writer.setMaxBufferedDocs(2);
Document doc = new Document();
doc.add(new Field("content", "aaa", Field.Store.YES, Field.Index.TOKENIZED, Field.TermVector.WITH_POSITIONS_OFFSETS));
for(int i=0;i<7;i++)
writer.addDocument(doc);
IndexCommitPoint cp = dp.snapshot();
copyFiles(dir, dp, cp);
writer.close();
copyFiles(dir, dp, cp);
writer = new IndexWriter(dir, true, new StandardAnalyzer(), dp,
IndexWriter.MaxFieldLength.LIMITED);
copyFiles(dir, dp, cp);
for(int i=0;i<7;i++)
writer.addDocument(doc);
copyFiles(dir, dp, cp);
writer.close();
copyFiles(dir, dp, cp);
dp.release();
writer = new IndexWriter(dir, true, new StandardAnalyzer(), dp,
IndexWriter.MaxFieldLength.LIMITED);
writer.close();
try {
copyFiles(dir, dp, cp);
fail("did not hit expected IOException");
} catch (IOException ioe) {
// expected
}
dir.close();
}
private void runTest(Directory dir) throws IOException { private void runTest(Directory dir) throws IOException {
// Run for ~7 seconds // Run for ~7 seconds
final long stopTime = System.currentTimeMillis() + 7000; final long stopTime = System.currentTimeMillis() + 7000;
@ -82,9 +120,9 @@ public class TestSnapshotDeletionPolicy extends LuceneTestCase
for(int i=0;i<27;i++) { for(int i=0;i<27;i++) {
try { try {
writer.addDocument(doc); writer.addDocument(doc);
} catch (IOException cie) { } catch (Throwable t) {
RuntimeException re = new RuntimeException("addDocument failed"); RuntimeException re = new RuntimeException("addDocument failed");
re.initCause(cie); re.initCause(t);
throw re; throw re;
} }
} }
@ -137,27 +175,9 @@ public class TestSnapshotDeletionPolicy extends LuceneTestCase
* just to test that the files indeed exist and are * just to test that the files indeed exist and are
* readable even while the index is changing. */ * readable even while the index is changing. */
public void backupIndex(Directory dir, SnapshotDeletionPolicy dp) throws IOException { public void backupIndex(Directory dir, SnapshotDeletionPolicy dp) throws IOException {
// To backup an index we first take a snapshot: // To backup an index we first take a snapshot:
IndexCommitPoint cp = dp.snapshot();
try { try {
copyFiles(dir, dp, dp.snapshot());
// While we hold the snapshot, and nomatter how long
// we take to do the backup, the IndexWriter will
// never delete the files in the snapshot:
Collection files = cp.getFileNames();
Iterator it = files.iterator();
while(it.hasNext()) {
final String fileName = (String) it.next();
// NOTE: in a real backup you would not use
// readFile; you would need to use something else
// that copies the file to a backup location. This
// could even be a spawned shell process (eg "tar",
// "zip") that takes the list of files and builds a
// backup.
readFile(dir, fileName);
}
} finally { } finally {
// Make sure to release the snapshot, otherwise these // Make sure to release the snapshot, otherwise these
// files will never be deleted during this IndexWriter // files will never be deleted during this IndexWriter
@ -166,6 +186,25 @@ public class TestSnapshotDeletionPolicy extends LuceneTestCase
} }
} }
private void copyFiles(Directory dir, SnapshotDeletionPolicy dp, IndexCommitPoint cp) throws IOException {
// While we hold the snapshot, and nomatter how long
// we take to do the backup, the IndexWriter will
// never delete the files in the snapshot:
Collection files = cp.getFileNames();
Iterator it = files.iterator();
while(it.hasNext()) {
final String fileName = (String) it.next();
// NOTE: in a real backup you would not use
// readFile; you would need to use something else
// that copies the file to a backup location. This
// could even be a spawned shell process (eg "tar",
// "zip") that takes the list of files and builds a
// backup.
readFile(dir, fileName);
}
}
byte[] buffer = new byte[4096]; byte[] buffer = new byte[4096];
private void readFile(Directory dir, String name) throws IOException { private void readFile(Directory dir, String name) throws IOException {