LUCENE-3606: Nuke IR.commit(), only SR.doCommit() left

git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene3606@1210247 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Uwe Schindler 2011-12-04 22:02:49 +00:00
parent 4bc66619f9
commit 92c0119b37
8 changed files with 46 additions and 319 deletions

View File

@ -1137,11 +1137,6 @@ public class MemoryIndex {
return false;
}
@Override
protected void doCommit(Map<String,String> commitUserData) {
if (DEBUG) System.err.println("MemoryIndexReader.doCommit");
}
@Override
protected void doClose() {
if (DEBUG) System.err.println("MemoryIndexReader.doClose");

View File

@ -44,18 +44,13 @@ import org.apache.lucene.util.MapBackedSet;
*/
class DirectoryReader extends IndexReader implements Cloneable {
protected Directory directory;
protected boolean readOnly;
protected boolean readOnly = true; // nocommit: remove this
IndexWriter writer;
private IndexDeletionPolicy deletionPolicy;
private Lock writeLock;
private final SegmentInfos segmentInfos;
private boolean stale;
private final int termInfosIndexDivisor;
private boolean rollbackHasChanges;
private SegmentReader[] subReaders;
private ReaderContext topLevelReaderContext;
private int[] starts; // 1st docno for each segment
@ -70,34 +65,22 @@ class DirectoryReader extends IndexReader implements Cloneable {
private final boolean applyAllDeletes;
// static IndexReader open(final Directory directory, final IndexDeletionPolicy deletionPolicy, final IndexCommit commit, final boolean readOnly,
// final int termInfosIndexDivisor) throws CorruptIndexException, IOException {
// return open(directory, deletionPolicy, commit, readOnly, termInfosIndexDivisor, null);
// }
static IndexReader open(final Directory directory, final IndexDeletionPolicy deletionPolicy, final IndexCommit commit, final boolean readOnly,
static IndexReader open(final Directory directory, final IndexCommit commit, final boolean readOnly,
final int termInfosIndexDivisor) throws CorruptIndexException, IOException {
return (IndexReader) new SegmentInfos.FindSegmentsFile(directory) {
@Override
protected Object doBody(String segmentFileName) throws CorruptIndexException, IOException {
SegmentInfos infos = new SegmentInfos();
infos.read(directory, segmentFileName);
return new DirectoryReader(directory, infos, deletionPolicy, readOnly, termInfosIndexDivisor);
return new DirectoryReader(directory, infos, readOnly, termInfosIndexDivisor);
}
}.run(commit);
}
/** Construct reading the named set of readers. */
// DirectoryReader(Directory directory, SegmentInfos sis, IndexDeletionPolicy deletionPolicy, boolean readOnly, int termInfosIndexDivisor) throws IOException {
// this(directory, sis, deletionPolicy, readOnly, termInfosIndexDivisor, null);
// }
/** Construct reading the named set of readers. */
DirectoryReader(Directory directory, SegmentInfos sis, IndexDeletionPolicy deletionPolicy, boolean readOnly, int termInfosIndexDivisor) throws IOException {
DirectoryReader(Directory directory, SegmentInfos sis, boolean readOnly, int termInfosIndexDivisor) throws IOException {
this.directory = directory;
this.readOnly = readOnly;
this.readOnly = true; // nocommit: remove readOnly at all
this.segmentInfos = sis;
this.deletionPolicy = deletionPolicy;
this.termInfosIndexDivisor = termInfosIndexDivisor;
readerFinishedListeners = new MapBackedSet<ReaderFinishedListener>(new ConcurrentHashMap<ReaderFinishedListener,Boolean>());
applyAllDeletes = false;
@ -281,9 +264,6 @@ class DirectoryReader extends IndexReader implements Cloneable {
@Override
public String toString() {
final StringBuilder buffer = new StringBuilder();
if (hasChanges) {
buffer.append("*");
}
buffer.append(getClass().getSimpleName());
buffer.append('(');
final String segmentsFile = segmentInfos.getCurrentSegmentFileName();
@ -348,21 +328,8 @@ class DirectoryReader extends IndexReader implements Cloneable {
// doOpenIfChanged calls ensureOpen
DirectoryReader newReader = doOpenIfChanged((SegmentInfos) segmentInfos.clone(), true, openReadOnly);
if (this != newReader) {
newReader.deletionPolicy = deletionPolicy;
}
newReader.writer = writer;
// If we're cloning a non-readOnly reader, move the
// writeLock (if there is one) to the new reader:
if (!openReadOnly && writeLock != null) {
// In near real-time search, reader is always readonly
assert writer == null;
newReader.writeLock = writeLock;
newReader.hasChanges = hasChanges;
newReader.hasDeletions = hasDeletions;
writeLock = null;
hasChanges = false;
}
newReader.hasDeletions = hasDeletions;
assert newReader.readerFinishedListeners != null;
return newReader;
@ -437,39 +404,15 @@ class DirectoryReader extends IndexReader implements Cloneable {
private synchronized IndexReader doOpenNoWriter(final boolean openReadOnly, IndexCommit commit) throws CorruptIndexException, IOException {
if (commit == null) {
if (hasChanges) {
// We have changes, which means we are not readOnly:
assert readOnly == false;
// and we hold the write lock:
assert writeLock != null;
// so no other writer holds the write lock, which
// means no changes could have been done to the index:
assert isCurrent();
if (openReadOnly) {
return clone(openReadOnly);
} else {
return null;
}
} else if (isCurrent()) {
if (openReadOnly != readOnly) {
// Just fallback to clone
return clone(openReadOnly);
} else {
return null;
}
if (isCurrent()) {
return null;
}
} else {
if (directory != commit.getDirectory()) {
throw new IOException("the specified commit does not match the specified Directory");
}
if (segmentInfos != null && commit.getSegmentsFileName().equals(segmentInfos.getCurrentSegmentFileName())) {
if (readOnly != openReadOnly) {
// Just fallback to clone
return clone(openReadOnly);
} else {
return null;
}
return null;
}
}
@ -599,145 +542,6 @@ class DirectoryReader extends IndexReader implements Cloneable {
throw new UnsupportedOperationException("please use MultiFields.getFields, or wrap your IndexReader with SlowMultiReaderWrapper, if you really need a top level Fields");
}
/**
* Tries to acquire the WriteLock on this directory. this method is only valid if this IndexReader is directory
* owner.
*
* @throws StaleReaderException if the index has changed since this reader was opened
* @throws CorruptIndexException if the index is corrupt
* @throws org.apache.lucene.store.LockObtainFailedException
* if another writer has this index open (<code>write.lock</code> could not be
* obtained)
* @throws IOException if there is a low-level IO error
*/
@Override
protected void acquireWriteLock() throws StaleReaderException, CorruptIndexException, LockObtainFailedException, IOException {
if (readOnly) {
// NOTE: we should not reach this code w/ the core
// IndexReader classes; however, an external subclass
// of IndexReader could reach this.
throw new UnsupportedOperationException("This IndexReader cannot make any changes to the index (it was opened with readOnly = true)");
}
if (segmentInfos != null) {
ensureOpen();
if (stale)
throw new StaleReaderException("IndexReader out of date and no longer valid for delete, undelete operations");
if (writeLock == null) {
Lock writeLock = directory.makeLock(IndexWriter.WRITE_LOCK_NAME);
if (!writeLock.obtain(IndexWriterConfig.WRITE_LOCK_TIMEOUT)) // obtain write lock
throw new LockObtainFailedException("Index locked for write: " + writeLock);
this.writeLock = writeLock;
// we have to check whether index has changed since this reader was opened.
// if so, this reader is no longer valid for deletion
if (SegmentInfos.readCurrentVersion(directory) > maxIndexVersion) {
stale = true;
this.writeLock.release();
this.writeLock = null;
throw new StaleReaderException("IndexReader out of date and no longer valid for delete, undelete operations");
}
}
}
}
/**
* Commit changes resulting from delete, undeleteAll operations
* <p/>
* If an exception is hit, then either no changes or all changes will have been committed to the index (transactional
* semantics).
*
* @throws IOException if there is a low-level IO error
*/
@Override
protected void doCommit(Map<String,String> commitUserData) throws IOException {
// poll subreaders for changes
for (int i = 0; !hasChanges && i < subReaders.length; i++) {
hasChanges |= subReaders[i].hasChanges;
}
if (hasChanges) {
segmentInfos.setUserData(commitUserData);
// Default deleter (for backwards compatibility) is
// KeepOnlyLastCommitDeleter:
// TODO: Decide what to do with InfoStream here? Use default or keep NO_OUTPUT?
IndexFileDeleter deleter = new IndexFileDeleter(directory,
deletionPolicy == null ? new KeepOnlyLastCommitDeletionPolicy() : deletionPolicy,
segmentInfos, InfoStream.NO_OUTPUT, null);
segmentInfos.updateGeneration(deleter.getLastSegmentInfos());
segmentInfos.changed();
// Checkpoint the state we are about to change, in
// case we have to roll back:
startCommit();
final List<SegmentInfo> rollbackSegments = segmentInfos.createBackupSegmentInfos(false);
boolean success = false;
try {
for (int i = 0; i < subReaders.length; i++)
subReaders[i].commit();
// Remove segments that contain only 100% deleted
// docs:
segmentInfos.pruneDeletedSegments();
// Sync all files we just wrote
directory.sync(segmentInfos.files(directory, false));
segmentInfos.commit(directory, segmentInfos.codecFormat());
success = true;
} finally {
if (!success) {
// Rollback changes that were made to
// SegmentInfos but failed to get [fully]
// committed. This way this reader instance
// remains consistent (matched to what's
// actually in the index):
rollbackCommit();
// Recompute deletable files & remove them (so
// partially written .del files, etc, are
// removed):
deleter.refresh();
// Restore all SegmentInfos (in case we pruned some)
segmentInfos.rollbackSegmentInfos(rollbackSegments);
}
}
// Have the deleter remove any now unreferenced
// files due to this commit:
deleter.checkpoint(segmentInfos, true);
deleter.close();
maxIndexVersion = segmentInfos.getVersion();
if (writeLock != null) {
writeLock.release(); // release write lock
writeLock = null;
}
}
hasChanges = false;
}
void startCommit() {
rollbackHasChanges = hasChanges;
for (int i = 0; i < subReaders.length; i++) {
subReaders[i].startCommit();
}
}
void rollbackCommit() {
hasChanges = rollbackHasChanges;
for (int i = 0; i < subReaders.length; i++) {
subReaders[i].rollbackCommit();
}
}
@Override
public long getUniqueTermCount() throws IOException {
return -1;

View File

@ -352,11 +352,6 @@ public class FilterIndexReader extends IndexReader {
ensureOpen();
return in.docFreq(field, t);
}
@Override
protected void doCommit(Map<String,String> commitUserData) throws IOException {
in.commit(commitUserData);
}
@Override
protected void doClose() throws IOException {

View File

@ -171,7 +171,6 @@ public abstract class IndexReader implements Cloneable,Closeable {
}
private volatile boolean closed;
protected boolean hasChanges;
private final AtomicInteger refCount = new AtomicInteger();
@ -239,9 +238,6 @@ public abstract class IndexReader implements Cloneable,Closeable {
@Override
public String toString() {
final StringBuilder buffer = new StringBuilder();
if (hasChanges) {
buffer.append('*');
}
buffer.append(getClass().getSimpleName());
buffer.append('(');
final IndexReader[] subReaders = getSequentialSubReaders();
@ -272,7 +268,6 @@ public abstract class IndexReader implements Cloneable,Closeable {
if (rc == 1) {
boolean success = false;
try {
commit();
doClose();
success = true;
} finally {
@ -461,7 +456,8 @@ public abstract class IndexReader implements Cloneable,Closeable {
}
private static IndexReader open(final Directory directory, final IndexDeletionPolicy deletionPolicy, final IndexCommit commit, final boolean readOnly, int termInfosIndexDivisor) throws CorruptIndexException, IOException {
return DirectoryReader.open(directory, deletionPolicy, commit, readOnly, termInfosIndexDivisor);
// nocommit: deletionPolicy is ignored -> remove it
return DirectoryReader.open(directory, commit, readOnly, termInfosIndexDivisor);
}
/**
@ -1073,62 +1069,6 @@ public abstract class IndexReader implements Cloneable,Closeable {
return null;
}
/** Does nothing by default. Subclasses that require a write lock for
* index modifications must implement this method. */
protected synchronized void acquireWriteLock() throws IOException {
/* NOOP */
}
/**
*
* @throws IOException
*/
public final synchronized void flush() throws IOException {
ensureOpen();
commit();
}
/**
* @param commitUserData Opaque Map (String -> String)
* that's recorded into the segments file in the index,
* and retrievable by {@link
* IndexReader#getCommitUserData}.
* @throws IOException
*/
public final synchronized void flush(Map<String, String> commitUserData) throws IOException {
ensureOpen();
commit(commitUserData);
}
/**
* Commit changes resulting from delete, undeleteAll operations
*
* If an exception is hit, then either no changes or all
* changes will have been committed to the index
* (transactional semantics).
* @throws IOException if there is a low-level IO error
*/
protected final synchronized void commit() throws IOException {
commit(null);
}
/**
* Commit changes resulting from delete, undeleteAll operations
*
* If an exception is hit, then either no changes or all
* changes will have been committed to the index
* (transactional semantics).
* @throws IOException if there is a low-level IO error
*/
public final synchronized void commit(Map<String, String> commitUserData) throws IOException {
// Don't call ensureOpen since we commit() on close
doCommit(commitUserData);
hasChanges = false;
}
/** Implements commit. */
protected abstract void doCommit(Map<String, String> commitUserData) throws IOException;
/**
* Closes files associated with this index.
* Also saves any new deletions to disk.

View File

@ -618,7 +618,7 @@ public class IndexWriter implements Closeable, TwoPhaseCommit {
SegmentReader sr = ent.getValue();
if (sr.hasChanges) {
assert infoIsLive(sr.getSegmentInfo(), "key=" + ent.getKey());
sr.doCommit(null);
sr.doCommit();
// Must checkpoint w/ deleter, because this
// segment reader will have created new _X_N.del
@ -650,7 +650,7 @@ public class IndexWriter implements Closeable, TwoPhaseCommit {
final SegmentReader sr = readerMap.get(new SegmentCacheKey(info, IOContext.Context.READ));
if (sr != null && sr.hasChanges) {
assert infoIsLive(info);
sr.doCommit(null);
sr.doCommit();
// Must checkpoint w/ deleter, because this
// segment reader will have created new _X_N.del
// file.

View File

@ -275,12 +275,6 @@ public class MultiReader extends IndexReader implements Cloneable {
}
return total;
}
@Override
protected void doCommit(Map<String,String> commitUserData) throws IOException {
for (int i = 0; i < subReaders.length; i++)
subReaders[i].commit(commitUserData);
}
@Override
protected synchronized void doClose() throws IOException {

View File

@ -427,12 +427,6 @@ public class ParallelReader extends IndexReader {
return readers.toArray(new IndexReader[readers.size()]);
}
@Override
protected void doCommit(Map<String,String> commitUserData) throws IOException {
for (final IndexReader reader : readers)
reader.commit(commitUserData);
}
@Override
protected synchronized void doClose() throws IOException {
for (int i = 0; i < readers.size(); i++) {

View File

@ -53,6 +53,7 @@ public class SegmentReader extends IndexReader implements Cloneable {
volatile BitVector liveDocs;
AtomicInteger liveDocsRef = null;
boolean hasChanges = false;
private boolean liveDocsDirty = false;
// TODO: we should move this tracking into SegmentInfo;
@ -307,24 +308,39 @@ public class SegmentReader extends IndexReader implements Cloneable {
return clone;
}
@Override
protected void doCommit(Map<String,String> commitUserData) throws IOException {
if (hasChanges) {
startCommit();
boolean success = false;
try {
commitChanges(commitUserData);
success = true;
} finally {
if (!success) {
rollbackCommit();
}
// nocommit: remove deletions from SR
void doCommit() throws IOException {
assert hasChanges;
startCommit();
boolean success = false;
try {
commitChanges();
success = true;
} finally {
if (!success) {
rollbackCommit();
}
}
}
// nocommit: remove deletions from SR
private synchronized void commitChanges(Map<String,String> commitUserData) throws IOException {
private void startCommit() {
rollbackSegmentInfo = (SegmentInfo) si.clone();
rollbackHasChanges = hasChanges;
rollbackDeletedDocsDirty = liveDocsDirty;
rollbackPendingDeleteCount = pendingDeleteCount;
}
// nocommit: remove deletions from SR
private void rollbackCommit() {
si.reset(rollbackSegmentInfo);
hasChanges = rollbackHasChanges;
liveDocsDirty = rollbackDeletedDocsDirty;
pendingDeleteCount = rollbackPendingDeleteCount;
}
// nocommit: remove deletions from SR
private synchronized void commitChanges() throws IOException {
if (liveDocsDirty) { // re-write deleted
si.advanceDelGen();
@ -366,6 +382,10 @@ public class SegmentReader extends IndexReader implements Cloneable {
@Override
protected void doClose() throws IOException {
if (hasChanges) {
doCommit();
}
termVectorsLocal.close();
fieldsReaderLocal.close();
@ -405,7 +425,6 @@ public class SegmentReader extends IndexReader implements Cloneable {
// nocommit: remove deletions from SR
synchronized void deleteDocument(int docNum) throws IOException {
ensureOpen();
acquireWriteLock();
hasChanges = true;
doDelete(docNum);
}
@ -691,20 +710,6 @@ public class SegmentReader extends IndexReader implements Cloneable {
si = info;
}
void startCommit() {
rollbackSegmentInfo = (SegmentInfo) si.clone();
rollbackHasChanges = hasChanges;
rollbackDeletedDocsDirty = liveDocsDirty;
rollbackPendingDeleteCount = pendingDeleteCount;
}
void rollbackCommit() {
si.reset(rollbackSegmentInfo);
hasChanges = rollbackHasChanges;
liveDocsDirty = rollbackDeletedDocsDirty;
pendingDeleteCount = rollbackPendingDeleteCount;
}
/** Returns the directory this index resides in. */
@Override
public Directory directory() {