org.elasticsearch.index.engine.SingleDocDirectoryReader Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of elasticsearch Show documentation
Show all versions of elasticsearch Show documentation
Elasticsearch subproject :server
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
package org.elasticsearch.index.engine;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.index.BinaryDocValues;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.FieldInfos;
import org.apache.lucene.index.Fields;
import org.apache.lucene.index.IndexCommit;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.LeafMetaData;
import org.apache.lucene.index.LeafReader;
import org.apache.lucene.index.NumericDocValues;
import org.apache.lucene.index.PointValues;
import org.apache.lucene.index.SortedDocValues;
import org.apache.lucene.index.SortedNumericDocValues;
import org.apache.lucene.index.SortedSetDocValues;
import org.apache.lucene.index.StoredFieldVisitor;
import org.apache.lucene.index.Terms;
import org.apache.lucene.store.ByteBuffersDirectory;
import org.apache.lucene.store.Directory;
import org.apache.lucene.util.Bits;
import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.core.internal.io.IOUtils;
import org.elasticsearch.index.mapper.DocumentParser;
import org.elasticsearch.index.mapper.MappingLookup;
import org.elasticsearch.index.mapper.ParsedDocument;
import org.elasticsearch.index.mapper.SourceToParse;
import org.elasticsearch.index.shard.ShardId;
import org.elasticsearch.index.translog.Translog;
import java.io.IOException;
import java.util.Collections;
import java.util.concurrent.atomic.AtomicReference;
/**
* A {@link DirectoryReader} contains a single leaf reader delegating to an in-memory Lucene segment that is lazily created from
* a single document.
*/
final class SingleDocDirectoryReader extends DirectoryReader {
private final SingleDocLeafReader leafReader;
SingleDocDirectoryReader(
ShardId shardId,
Translog.Index operation,
MappingLookup mappingLookup,
DocumentParser documentParser,
Analyzer analyzer
) throws IOException {
this(new SingleDocLeafReader(shardId, operation, mappingLookup, documentParser, analyzer));
}
private SingleDocDirectoryReader(SingleDocLeafReader leafReader) throws IOException {
super(leafReader.directory, new LeafReader[] { leafReader }, null);
this.leafReader = leafReader;
}
boolean assertMemorySegmentStatus(boolean loaded) {
return leafReader.assertMemorySegmentStatus(loaded);
}
private static UnsupportedOperationException unsupported() {
assert false : "unsupported operation";
return new UnsupportedOperationException();
}
@Override
protected DirectoryReader doOpenIfChanged() {
throw unsupported();
}
@Override
protected DirectoryReader doOpenIfChanged(IndexCommit commit) {
throw unsupported();
}
@Override
protected DirectoryReader doOpenIfChanged(IndexWriter writer, boolean applyAllDeletes) {
throw unsupported();
}
@Override
public long getVersion() {
throw unsupported();
}
@Override
public boolean isCurrent() {
throw unsupported();
}
@Override
public IndexCommit getIndexCommit() {
throw unsupported();
}
@Override
protected void doClose() throws IOException {
leafReader.close();
}
@Override
public CacheHelper getReaderCacheHelper() {
return leafReader.getReaderCacheHelper();
}
private static class SingleDocLeafReader extends LeafReader {
private final ShardId shardId;
private final Translog.Index operation;
private final MappingLookup mappingLookup;
private final DocumentParser documentParser;
private final Analyzer analyzer;
private final Directory directory;
private final AtomicReference delegate = new AtomicReference<>();
SingleDocLeafReader(
ShardId shardId,
Translog.Index operation,
MappingLookup mappingLookup,
DocumentParser documentParser,
Analyzer analyzer
) {
this.shardId = shardId;
this.operation = operation;
this.mappingLookup = mappingLookup;
this.documentParser = documentParser;
this.analyzer = analyzer;
this.directory = new ByteBuffersDirectory();
}
private LeafReader getDelegate() {
ensureOpen();
LeafReader reader = delegate.get();
if (reader == null) {
synchronized (this) {
reader = delegate.get();
if (reader == null) {
reader = createInMemoryLeafReader();
final LeafReader existing = delegate.getAndSet(reader);
assert existing == null;
}
}
}
return reader;
}
private LeafReader createInMemoryLeafReader() {
assert Thread.holdsLock(this);
final ParsedDocument parsedDocs = documentParser.parseDocument(
new SourceToParse(
shardId.getIndexName(),
operation.type(),
operation.id(),
operation.source(),
XContentHelper.xContentType(operation.source()),
operation.routing(),
Collections.emptyMap()
),
mappingLookup
);
parsedDocs.updateSeqID(operation.seqNo(), operation.primaryTerm());
parsedDocs.version().setLongValue(operation.version());
final IndexWriterConfig writeConfig = new IndexWriterConfig(analyzer).setOpenMode(IndexWriterConfig.OpenMode.CREATE);
try (IndexWriter writer = new IndexWriter(directory, writeConfig)) {
writer.addDocument(parsedDocs.rootDoc());
final DirectoryReader reader = open(writer);
if (reader.leaves().size() != 1 || reader.leaves().get(0).reader().numDocs() != 1) {
reader.close();
throw new IllegalStateException(
"Expected a single document segment; "
+ "but ["
+ reader.leaves().size()
+ " segments with "
+ reader.leaves().get(0).reader().numDocs()
+ " documents"
);
}
return reader.leaves().get(0).reader();
} catch (IOException e) {
throw new EngineException(shardId, "failed to create an in-memory segment for get [" + operation.id() + "]", e);
}
}
@Override
public CacheHelper getCoreCacheHelper() {
return getDelegate().getCoreCacheHelper();
}
@Override
public CacheHelper getReaderCacheHelper() {
return getDelegate().getReaderCacheHelper();
}
@Override
public Terms terms(String field) throws IOException {
return getDelegate().terms(field);
}
@Override
public NumericDocValues getNumericDocValues(String field) throws IOException {
return getDelegate().getNumericDocValues(field);
}
@Override
public BinaryDocValues getBinaryDocValues(String field) throws IOException {
return getDelegate().getBinaryDocValues(field);
}
@Override
public SortedDocValues getSortedDocValues(String field) throws IOException {
return getDelegate().getSortedDocValues(field);
}
@Override
public SortedNumericDocValues getSortedNumericDocValues(String field) throws IOException {
return getDelegate().getSortedNumericDocValues(field);
}
@Override
public SortedSetDocValues getSortedSetDocValues(String field) throws IOException {
return getDelegate().getSortedSetDocValues(field);
}
@Override
public NumericDocValues getNormValues(String field) throws IOException {
return getDelegate().getNormValues(field);
}
@Override
public FieldInfos getFieldInfos() {
return getDelegate().getFieldInfos();
}
@Override
public Bits getLiveDocs() {
return getDelegate().getLiveDocs();
}
@Override
public PointValues getPointValues(String field) throws IOException {
return getDelegate().getPointValues(field);
}
@Override
public void checkIntegrity() throws IOException {}
@Override
public LeafMetaData getMetaData() {
return getDelegate().getMetaData();
}
@Override
public Fields getTermVectors(int docID) throws IOException {
return getDelegate().getTermVectors(docID);
}
@Override
public int numDocs() {
return 1;
}
@Override
public int maxDoc() {
return 1;
}
synchronized boolean assertMemorySegmentStatus(boolean loaded) {
if (loaded) {
assert delegate.get() != null
: "Expected an in memory segment was loaded; but it wasn't. Please check the reader wrapper implementation";
} else {
assert delegate.get() == null
: "Expected an in memory segment wasn't loaded; but it was. Please check the reader wrapper implementation";
}
return true;
}
@Override
public void document(int docID, StoredFieldVisitor visitor) throws IOException {
assert assertMemorySegmentStatus(true);
getDelegate().document(docID, visitor);
}
@Override
protected void doClose() throws IOException {
IOUtils.close(delegate.get(), directory);
}
}
}