| Constructor: |
MultiSegmentReader(Directory directory,
SegmentInfos sis,
boolean closeDirectory,
boolean readOnly) throws IOException {
super(directory, sis, closeDirectory, readOnly);
// To reduce the chance of hitting FileNotFound
// (and having to retry), we open segments in
// reverse because IndexWriter merges & deletes
// the newest segments first.
SegmentReader[] readers = new SegmentReader[sis.size()];
for (int i = sis.size()-1; i >= 0; i--) {
try {
readers[i] = SegmentReader.get(readOnly, sis.info(i));
} catch (IOException e) {
// Close all readers we had opened:
for(i++;i< sis.size();i++) {
try {
readers[i].close();
} catch (IOException ignore) {
// keep going - we want to clean up as much as possible
}
}
throw e;
}
}
initialize(readers);
}
Construct reading the named set of readers. |
MultiSegmentReader(Directory directory,
SegmentInfos infos,
boolean closeDirectory,
SegmentReader[] oldReaders,
int[] oldStarts,
Map oldNormsCache,
boolean readOnly) throws IOException {
super(directory, infos, closeDirectory, readOnly);
// we put the old SegmentReaders in a map, that allows us
// to lookup a reader using its segment name
Map segmentReaders = new HashMap();
if (oldReaders != null) {
// create a Map SegmentName- >SegmentReader
for (int i = 0; i < oldReaders.length; i++) {
segmentReaders.put(oldReaders[i].getSegmentName(), new Integer(i));
}
}
SegmentReader[] newReaders = new SegmentReader[infos.size()];
// remember which readers are shared between the old and the re-opened
// MultiSegmentReader - we have to incRef those readers
boolean[] readerShared = new boolean[infos.size()];
for (int i = infos.size() - 1; i >=0; i--) {
// find SegmentReader for this segment
Integer oldReaderIndex = (Integer) segmentReaders.get(infos.info(i).name);
if (oldReaderIndex == null) {
// this is a new segment, no old SegmentReader can be reused
newReaders[i] = null;
} else {
// there is an old reader for this segment - we'll try to reopen it
newReaders[i] = oldReaders[oldReaderIndex.intValue()];
}
boolean success = false;
try {
SegmentReader newReader;
if (newReaders[i] == null || infos.info(i).getUseCompoundFile() != newReaders[i].getSegmentInfo().getUseCompoundFile()) {
// this is a new reader; in case we hit an exception we can close it safely
newReader = SegmentReader.get(readOnly, infos.info(i));
} else {
newReader = (SegmentReader) newReaders[i].reopenSegment(infos.info(i));
}
if (newReader == newReaders[i]) {
// this reader will be shared between the old and the new one,
// so we must incRef it
readerShared[i] = true;
newReader.incRef();
} else {
readerShared[i] = false;
newReaders[i] = newReader;
}
success = true;
} finally {
if (!success) {
for (i++; i < infos.size(); i++) {
if (newReaders[i] != null) {
try {
if (!readerShared[i]) {
// this is a new subReader that is not used by the old one,
// we can close it
newReaders[i].close();
} else {
// this subReader is also used by the old reader, so instead
// closing we must decRef it
newReaders[i].decRef();
}
} catch (IOException ignore) {
// keep going - we want to clean up as much as possible
}
}
}
}
}
}
// initialize the readers to calculate maxDoc before we try to reuse the old normsCache
initialize(newReaders);
// try to copy unchanged norms from the old normsCache to the new one
if (oldNormsCache != null) {
Iterator it = oldNormsCache.entrySet().iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
String field = (String) entry.getKey();
if (!hasNorms(field)) {
continue;
}
byte[] oldBytes = (byte[]) entry.getValue();
byte[] bytes = new byte[maxDoc()];
for (int i = 0; i < subReaders.length; i++) {
Integer oldReaderIndex = ((Integer) segmentReaders.get(subReaders[i].getSegmentName()));
// this SegmentReader was not re-opened, we can copy all of its norms
if (oldReaderIndex != null &&
(oldReaders[oldReaderIndex.intValue()] == subReaders[i]
|| oldReaders[oldReaderIndex.intValue()].norms.get(field) == subReaders[i].norms.get(field))) {
// we don't have to synchronize here: either this constructor is called from a SegmentReader,
// in which case no old norms cache is present, or it is called from MultiReader.reopen(),
// which is synchronized
System.arraycopy(oldBytes, oldStarts[oldReaderIndex.intValue()], bytes, starts[i], starts[i+1] - starts[i]);
} else {
subReaders[i].norms(field, bytes, starts[i]);
}
}
normsCache.put(field, bytes); // update cache
}
}
}
|
| Method from org.apache.lucene.index.MultiSegmentReader Detail: |
protected void commitChanges() throws IOException {
for (int i = 0; i < subReaders.length; i++)
subReaders[i].commit();
}
|
protected synchronized void doClose() throws IOException {
for (int i = 0; i < subReaders.length; i++)
subReaders[i].decRef();
// maybe close directory
super.doClose();
}
|
protected void doDelete(int n) throws IOException, CorruptIndexException {
numDocs = -1; // invalidate cache
int i = readerIndex(n); // find segment num
subReaders[i].deleteDocument(n - starts[i]); // dispatch to segment reader
hasDeletions = true;
}
|
protected synchronized DirectoryIndexReader doReopen(SegmentInfos infos) throws IOException, CorruptIndexException {
if (infos.size() == 1) {
// The index has only one segment now, so we can't refresh the MultiSegmentReader.
// Return a new [ReadOnly]SegmentReader instead
return SegmentReader.get(readOnly, infos, infos.info(0), false);
} else if (readOnly) {
return new ReadOnlyMultiSegmentReader(directory, infos, closeDirectory, subReaders, starts, normsCache);
} else {
return new MultiSegmentReader(directory, infos, closeDirectory, subReaders, starts, normsCache, false);
}
}
|
protected void doSetNorm(int n,
String field,
byte value) throws IOException, CorruptIndexException {
synchronized (normsCache) {
normsCache.remove(field); // clear cache
}
int i = readerIndex(n); // find segment num
subReaders[i].setNorm(n-starts[i], field, value); // dispatch
}
|
protected void doUndeleteAll() throws IOException, CorruptIndexException {
for (int i = 0; i < subReaders.length; i++)
subReaders[i].undeleteAll();
hasDeletions = false;
numDocs = -1; // invalidate cache
}
|
public int docFreq(Term t) throws IOException {
ensureOpen();
int total = 0; // sum freqs in segments
for (int i = 0; i < subReaders.length; i++)
total += subReaders[i].docFreq(t);
return total;
}
|
public Document document(int n,
FieldSelector fieldSelector) throws IOException, CorruptIndexException {
ensureOpen();
int i = readerIndex(n); // find segment num
return subReaders[i].document(n - starts[i], fieldSelector); // dispatch to segment reader
}
|
public Collection getFieldNames(IndexReader.FieldOption fieldNames) {
ensureOpen();
return getFieldNames(fieldNames, this.subReaders);
}
|
static Collection getFieldNames(IndexReader.FieldOption fieldNames,
IndexReader[] subReaders) {
// maintain a unique set of field names
Set fieldSet = new HashSet();
for (int i = 0; i < subReaders.length; i++) {
IndexReader reader = subReaders[i];
Collection names = reader.getFieldNames(fieldNames);
fieldSet.addAll(names);
}
return fieldSet;
}
|
SegmentReader[] getSubReaders() {
return subReaders;
}
|
public TermFreqVector getTermFreqVector(int n,
String field) throws IOException {
ensureOpen();
int i = readerIndex(n); // find segment num
return subReaders[i].getTermFreqVector(n - starts[i], field);
}
|
public void getTermFreqVector(int docNumber,
TermVectorMapper mapper) throws IOException {
ensureOpen();
int i = readerIndex(docNumber); // find segment num
subReaders[i].getTermFreqVector(docNumber - starts[i], mapper);
}
|
public void getTermFreqVector(int docNumber,
String field,
TermVectorMapper mapper) throws IOException {
ensureOpen();
int i = readerIndex(docNumber); // find segment num
subReaders[i].getTermFreqVector(docNumber - starts[i], field, mapper);
}
|
public TermFreqVector[] getTermFreqVectors(int n) throws IOException {
ensureOpen();
int i = readerIndex(n); // find segment num
return subReaders[i].getTermFreqVectors(n - starts[i]); // dispatch to segment
}
|
public int getTermInfosIndexDivisor() throws IllegalStateException {
if (subReaders.length > 0)
return subReaders[0].getTermInfosIndexDivisor();
else
throw new IllegalStateException("no readers");
}
|
public boolean hasDeletions() {
// Don't call ensureOpen() here (it could affect performance)
return hasDeletions;
}
|
public boolean hasNorms(String field) throws IOException {
ensureOpen();
for (int i = 0; i < subReaders.length; i++) {
if (subReaders[i].hasNorms(field)) return true;
}
return false;
}
|
public boolean isDeleted(int n) {
// Don't call ensureOpen() here (it could affect performance)
final int i = readerIndex(n); // find segment num
return subReaders[i].isDeleted(n - starts[i]); // dispatch to segment reader
}
|
public boolean isOptimized() {
return false;
}
|
public int maxDoc() {
// Don't call ensureOpen() here (it could affect performance)
return maxDoc;
}
|
public synchronized byte[] norms(String field) throws IOException {
ensureOpen();
byte[] bytes = (byte[])normsCache.get(field);
if (bytes != null)
return bytes; // cache hit
if (!hasNorms(field))
return fakeNorms();
bytes = new byte[maxDoc()];
for (int i = 0; i < subReaders.length; i++)
subReaders[i].norms(field, bytes, starts[i]);
normsCache.put(field, bytes); // update cache
return bytes;
}
|
public synchronized void norms(String field,
byte[] result,
int offset) throws IOException {
ensureOpen();
byte[] bytes = (byte[])normsCache.get(field);
if (bytes==null && !hasNorms(field)) bytes=fakeNorms();
if (bytes != null) // cache hit
System.arraycopy(bytes, 0, result, offset, maxDoc());
for (int i = 0; i < subReaders.length; i++) // read from segments
subReaders[i].norms(field, result, offset + starts[i]);
}
|
public synchronized int numDocs() {
// Don't call ensureOpen() here (it could affect performance)
if (numDocs == -1) { // check cache
int n = 0; // cache miss--recompute
for (int i = 0; i < subReaders.length; i++)
n += subReaders[i].numDocs(); // sum from readers
numDocs = n;
}
return numDocs;
}
|
static final int readerIndex(int n,
int[] starts,
int numSubReaders) {
// find reader for doc n:
int lo = 0; // search starts array
int hi = numSubReaders - 1; // for first element less
while (hi >= lo) {
int mid = (lo + hi) > > > 1;
int midValue = starts[mid];
if (n < midValue)
hi = mid - 1;
else if (n > midValue)
lo = mid + 1;
else { // found a match
while (mid+1 < numSubReaders && starts[mid+1] == midValue) {
mid++; // scan to last match
}
return mid;
}
}
return hi;
}
|
void rollbackCommit() {
super.rollbackCommit();
for (int i = 0; i < subReaders.length; i++) {
subReaders[i].rollbackCommit();
}
}
|
public void setTermInfosIndexDivisor(int indexDivisor) throws IllegalStateException {
for (int i = 0; i < subReaders.length; i++)
subReaders[i].setTermInfosIndexDivisor(indexDivisor);
}
|
void startCommit() {
super.startCommit();
for (int i = 0; i < subReaders.length; i++) {
subReaders[i].startCommit();
}
}
|
public TermDocs termDocs() throws IOException {
ensureOpen();
return new MultiTermDocs(subReaders, starts);
}
|
public TermPositions termPositions() throws IOException {
ensureOpen();
return new MultiTermPositions(subReaders, starts);
}
|
public TermEnum terms() throws IOException {
ensureOpen();
return new MultiTermEnum(subReaders, starts, null);
}
|
public TermEnum terms(Term term) throws IOException {
ensureOpen();
return new MultiTermEnum(subReaders, starts, term);
}
|