Search in sources :

Example 11 with Releasable

use of org.elasticsearch.common.lease.Releasable in project elasticsearch by elastic.

the class InternalEngine method index.

@Override
public IndexResult index(Index index) throws IOException {
    final boolean doThrottle = index.origin().isRecovery() == false;
    try (ReleasableLock releasableLock = readLock.acquire()) {
        ensureOpen();
        assert assertSequenceNumber(index.origin(), index.seqNo());
        assert assertVersionType(index);
        final Translog.Location location;
        long seqNo = index.seqNo();
        try (Releasable ignored = acquireLock(index.uid());
            Releasable indexThrottle = doThrottle ? () -> {
            } : throttle.acquireThrottle()) {
            lastWriteNanos = index.startTime();
            /* if we have an autoGeneratedID that comes into the engine we can potentially optimize
                 * and just use addDocument instead of updateDocument and skip the entire version and index lookup across the board.
                 * Yet, we have to deal with multiple document delivery, for this we use a property of the document that is added
                 * to detect if it has potentially been added before. We use the documents timestamp for this since it's something
                 * that:
                 *  - doesn't change per document
                 *  - is preserved in the transaction log
                 *  - and is assigned before we start to index / replicate
                 * NOTE: it's not important for this timestamp to be consistent across nodes etc. it's just a number that is in the common
                 * case increasing and can be used in the failure case when we retry and resent documents to establish a happens before relationship.
                 * for instance:
                 *  - doc A has autoGeneratedIdTimestamp = 10, isRetry = false
                 *  - doc B has autoGeneratedIdTimestamp = 9, isRetry = false
                 *
                 *  while both docs are in in flight, we disconnect on one node, reconnect and send doc A again
                 *  - now doc A' has autoGeneratedIdTimestamp = 10, isRetry = true
                 *
                 *  if A' arrives on the shard first we update maxUnsafeAutoIdTimestamp to 10 and use update document. All subsequent
                 *  documents that arrive (A and B) will also use updateDocument since their timestamps are less than maxUnsafeAutoIdTimestamp.
                 *  While this is not strictly needed for doc B it is just much simpler to implement since it will just de-optimize some doc in the worst case.
                 *
                 *  if A arrives on the shard first we use addDocument since maxUnsafeAutoIdTimestamp is < 10. A` will then just be skipped or calls
                 *  updateDocument.
                 */
            long currentVersion;
            final boolean deleted;
            // if anything is fishy here ie. there is a retry we go and force updateDocument below so we are updating the document in the
            // lucene index without checking the version map but we still do the version check
            final boolean forceUpdateDocument;
            final boolean canOptimizeAddDocument = canOptimizeAddDocument(index);
            if (canOptimizeAddDocument) {
                forceUpdateDocument = isForceUpdateDocument(index);
                currentVersion = Versions.NOT_FOUND;
                deleted = true;
            } else {
                // update the document
                // we don't force it - it depends on the version
                forceUpdateDocument = false;
                final VersionValue versionValue = versionMap.getUnderLock(index.uid());
                assert incrementVersionLookup();
                if (versionValue == null) {
                    currentVersion = loadCurrentVersionFromIndex(index.uid());
                    deleted = currentVersion == Versions.NOT_FOUND;
                } else {
                    currentVersion = checkDeletedAndGCed(versionValue);
                    deleted = versionValue.delete();
                }
            }
            final long expectedVersion = index.version();
            Optional<IndexResult> resultOnVersionConflict;
            try {
                final boolean isVersionConflict = checkVersionConflict(index, currentVersion, expectedVersion, deleted);
                resultOnVersionConflict = isVersionConflict ? Optional.of(new IndexResult(currentVersion, index.seqNo(), false)) : Optional.empty();
            } catch (IllegalArgumentException | VersionConflictEngineException ex) {
                resultOnVersionConflict = Optional.of(new IndexResult(ex, currentVersion, index.seqNo()));
            }
            final IndexResult indexResult;
            if (resultOnVersionConflict.isPresent()) {
                indexResult = resultOnVersionConflict.get();
            } else {
                // no version conflict
                if (index.origin() == Operation.Origin.PRIMARY) {
                    seqNo = seqNoService().generateSeqNo();
                }
                indexResult = indexIntoLucene(index, seqNo, currentVersion, deleted, forceUpdateDocument, canOptimizeAddDocument, expectedVersion);
            }
            if (indexResult.hasFailure() == false) {
                location = index.origin() != Operation.Origin.LOCAL_TRANSLOG_RECOVERY ? translog.add(new Translog.Index(index, indexResult)) : null;
                indexResult.setTranslogLocation(location);
            }
            indexResult.setTook(System.nanoTime() - index.startTime());
            indexResult.freeze();
            return indexResult;
        } finally {
            if (seqNo != SequenceNumbersService.UNASSIGNED_SEQ_NO) {
                seqNoService().markSeqNoAsCompleted(seqNo);
            }
        }
    } catch (RuntimeException | IOException e) {
        try {
            maybeFailEngine("index", e);
        } catch (Exception inner) {
            e.addSuppressed(inner);
        }
        throw e;
    }
}
Also used : IOException(java.io.IOException) ReleasableLock(org.elasticsearch.common.util.concurrent.ReleasableLock) AlreadyClosedException(org.apache.lucene.store.AlreadyClosedException) LockObtainFailedException(org.apache.lucene.store.LockObtainFailedException) TranslogCorruptedException(org.elasticsearch.index.translog.TranslogCorruptedException) IOException(java.io.IOException) IndexFormatTooOldException(org.apache.lucene.index.IndexFormatTooOldException) Translog(org.elasticsearch.index.translog.Translog) Releasable(org.elasticsearch.common.lease.Releasable)

Example 12 with Releasable

use of org.elasticsearch.common.lease.Releasable in project elasticsearch by elastic.

the class TransportReplicationActionTests method mockIndexShard.

private IndexShard mockIndexShard(ShardId shardId, ClusterService clusterService) {
    final IndexShard indexShard = mock(IndexShard.class);
    doAnswer(invocation -> {
        ActionListener<Releasable> callback = (ActionListener<Releasable>) invocation.getArguments()[0];
        count.incrementAndGet();
        callback.onResponse(count::decrementAndGet);
        return null;
    }).when(indexShard).acquirePrimaryOperationLock(any(ActionListener.class), anyString());
    doAnswer(invocation -> {
        long term = (Long) invocation.getArguments()[0];
        ActionListener<Releasable> callback = (ActionListener<Releasable>) invocation.getArguments()[1];
        final long primaryTerm = indexShard.getPrimaryTerm();
        if (term < primaryTerm) {
            throw new IllegalArgumentException(String.format(Locale.ROOT, "%s operation term [%d] is too old (current [%d])", shardId, term, primaryTerm));
        }
        count.incrementAndGet();
        callback.onResponse(count::decrementAndGet);
        return null;
    }).when(indexShard).acquireReplicaOperationLock(anyLong(), any(ActionListener.class), anyString());
    when(indexShard.routingEntry()).thenAnswer(invocationOnMock -> {
        final ClusterState state = clusterService.state();
        final RoutingNode node = state.getRoutingNodes().node(state.nodes().getLocalNodeId());
        final ShardRouting routing = node.getByShardId(shardId);
        if (routing == null) {
            throw new ShardNotFoundException(shardId, "shard is no longer assigned to current node");
        }
        return routing;
    });
    when(indexShard.state()).thenAnswer(invocationOnMock -> isRelocated.get() ? IndexShardState.RELOCATED : IndexShardState.STARTED);
    doThrow(new AssertionError("failed shard is not supported")).when(indexShard).failShard(anyString(), any(Exception.class));
    when(indexShard.getPrimaryTerm()).thenAnswer(i -> clusterService.state().metaData().getIndexSafe(shardId.getIndex()).primaryTerm(shardId.id()));
    return indexShard;
}
Also used : ClusterState(org.elasticsearch.cluster.ClusterState) IndexShard(org.elasticsearch.index.shard.IndexShard) ElasticsearchException(org.elasticsearch.ElasticsearchException) AlreadyClosedException(org.apache.lucene.store.AlreadyClosedException) IndexClosedException(org.elasticsearch.indices.IndexClosedException) NodeClosedException(org.elasticsearch.node.NodeClosedException) ShardNotFoundException(org.elasticsearch.index.shard.ShardNotFoundException) IndexNotFoundException(org.elasticsearch.index.IndexNotFoundException) NoNodeAvailableException(org.elasticsearch.client.transport.NoNodeAvailableException) TransportException(org.elasticsearch.transport.TransportException) IndexShardClosedException(org.elasticsearch.index.shard.IndexShardClosedException) ClusterBlockException(org.elasticsearch.cluster.block.ClusterBlockException) IOException(java.io.IOException) UnavailableShardsException(org.elasticsearch.action.UnavailableShardsException) ExecutionException(java.util.concurrent.ExecutionException) ActionListener(org.elasticsearch.action.ActionListener) RoutingNode(org.elasticsearch.cluster.routing.RoutingNode) ShardNotFoundException(org.elasticsearch.index.shard.ShardNotFoundException) Matchers.anyLong(org.mockito.Matchers.anyLong) Releasable(org.elasticsearch.common.lease.Releasable) TestShardRouting(org.elasticsearch.cluster.routing.TestShardRouting) ShardRouting(org.elasticsearch.cluster.routing.ShardRouting)

Example 13 with Releasable

use of org.elasticsearch.common.lease.Releasable in project elasticsearch by elastic.

the class TransportReplicationActionTests method testPrimaryReference.

public void testPrimaryReference() throws Exception {
    final IndexShard shard = mock(IndexShard.class);
    final long primaryTerm = 1 + randomInt(200);
    when(shard.getPrimaryTerm()).thenReturn(primaryTerm);
    AtomicBoolean closed = new AtomicBoolean();
    Releasable releasable = () -> {
        if (closed.compareAndSet(false, true) == false) {
            fail("releasable is closed twice");
        }
    };
    TestAction.PrimaryShardReference primary = action.new PrimaryShardReference(shard, releasable);
    final Request request = new Request();
    Request replicaRequest = (Request) primary.perform(request).replicaRequest;
    assertThat(replicaRequest.primaryTerm(), equalTo(primaryTerm));
    final ElasticsearchException exception = new ElasticsearchException("testing");
    primary.failShard("test", exception);
    verify(shard).failShard("test", exception);
    primary.close();
    assertTrue(closed.get());
}
Also used : AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) IndexShard(org.elasticsearch.index.shard.IndexShard) TransportRequest(org.elasticsearch.transport.TransportRequest) CloseIndexRequest(org.elasticsearch.action.admin.indices.close.CloseIndexRequest) Releasable(org.elasticsearch.common.lease.Releasable) ElasticsearchException(org.elasticsearch.ElasticsearchException)

Example 14 with Releasable

use of org.elasticsearch.common.lease.Releasable in project elasticsearch by elastic.

the class TransportWriteActionTests method mockIndexShard.

private IndexShard mockIndexShard(ShardId shardId, ClusterService clusterService) {
    final IndexShard indexShard = mock(IndexShard.class);
    doAnswer(invocation -> {
        ActionListener<Releasable> callback = (ActionListener<Releasable>) invocation.getArguments()[0];
        count.incrementAndGet();
        callback.onResponse(count::decrementAndGet);
        return null;
    }).when(indexShard).acquirePrimaryOperationLock(any(ActionListener.class), anyString());
    doAnswer(invocation -> {
        long term = (Long) invocation.getArguments()[0];
        ActionListener<Releasable> callback = (ActionListener<Releasable>) invocation.getArguments()[1];
        final long primaryTerm = indexShard.getPrimaryTerm();
        if (term < primaryTerm) {
            throw new IllegalArgumentException(String.format(Locale.ROOT, "%s operation term [%d] is too old (current [%d])", shardId, term, primaryTerm));
        }
        count.incrementAndGet();
        callback.onResponse(count::decrementAndGet);
        return null;
    }).when(indexShard).acquireReplicaOperationLock(anyLong(), any(ActionListener.class), anyString());
    when(indexShard.routingEntry()).thenAnswer(invocationOnMock -> {
        final ClusterState state = clusterService.state();
        final RoutingNode node = state.getRoutingNodes().node(state.nodes().getLocalNodeId());
        final ShardRouting routing = node.getByShardId(shardId);
        if (routing == null) {
            throw new ShardNotFoundException(shardId, "shard is no longer assigned to current node");
        }
        return routing;
    });
    when(indexShard.state()).thenAnswer(invocationOnMock -> isRelocated.get() ? IndexShardState.RELOCATED : IndexShardState.STARTED);
    doThrow(new AssertionError("failed shard is not supported")).when(indexShard).failShard(anyString(), any(Exception.class));
    when(indexShard.getPrimaryTerm()).thenAnswer(i -> clusterService.state().metaData().getIndexSafe(shardId.getIndex()).primaryTerm(shardId.id()));
    return indexShard;
}
Also used : ClusterState(org.elasticsearch.cluster.ClusterState) IndexShard(org.elasticsearch.index.shard.IndexShard) ElasticsearchException(org.elasticsearch.ElasticsearchException) NodeClosedException(org.elasticsearch.node.NodeClosedException) ShardNotFoundException(org.elasticsearch.index.shard.ShardNotFoundException) NoNodeAvailableException(org.elasticsearch.client.transport.NoNodeAvailableException) TransportException(org.elasticsearch.transport.TransportException) ExecutionException(java.util.concurrent.ExecutionException) ActionListener(org.elasticsearch.action.ActionListener) RoutingNode(org.elasticsearch.cluster.routing.RoutingNode) ShardNotFoundException(org.elasticsearch.index.shard.ShardNotFoundException) Matchers.anyLong(org.mockito.Matchers.anyLong) Releasable(org.elasticsearch.common.lease.Releasable) TestShardRouting(org.elasticsearch.cluster.routing.TestShardRouting) ShardRouting(org.elasticsearch.cluster.routing.ShardRouting)

Example 15 with Releasable

use of org.elasticsearch.common.lease.Releasable in project elasticsearch by elastic.

the class TcpTransport method sendRequestToChannel.

private void sendRequestToChannel(DiscoveryNode node, final Channel targetChannel, final long requestId, final String action, final TransportRequest request, TransportRequestOptions options, Version channelVersion, byte status) throws IOException, TransportException {
    if (compress) {
        options = TransportRequestOptions.builder(options).withCompress(true).build();
    }
    status = TransportStatus.setRequest(status);
    ReleasableBytesStreamOutput bStream = new ReleasableBytesStreamOutput(bigArrays);
    // we wrap this in a release once since if the onRequestSent callback throws an exception
    // we might release things twice and this should be prevented
    final Releasable toRelease = Releasables.releaseOnce(() -> Releasables.close(bStream.bytes()));
    boolean addedReleaseListener = false;
    StreamOutput stream = bStream;
    try {
        // the header part is compressed, and the "body" can't be extracted as compressed
        if (options.compress() && canCompress(request)) {
            status = TransportStatus.setCompress(status);
            stream = CompressorFactory.COMPRESSOR.streamOutput(stream);
        }
        // we pick the smallest of the 2, to support both backward and forward compatibility
        // note, this is the only place we need to do this, since from here on, we use the serialized version
        // as the version to use also when the node receiving this request will send the response with
        Version version = Version.min(getCurrentVersion(), channelVersion);
        stream.setVersion(version);
        threadPool.getThreadContext().writeTo(stream);
        stream.writeString(action);
        BytesReference message = buildMessage(requestId, status, node.getVersion(), request, stream, bStream);
        final TransportRequestOptions finalOptions = options;
        Runnable onRequestSent = () -> {
            // this might be called in a different thread
            try {
                toRelease.close();
            } finally {
                transportServiceAdapter.onRequestSent(node, requestId, action, request, finalOptions);
            }
        };
        addedReleaseListener = internalSendMessage(targetChannel, message, onRequestSent);
    } finally {
        IOUtils.close(stream);
        if (!addedReleaseListener) {
            toRelease.close();
        }
    }
}
Also used : BytesReference(org.elasticsearch.common.bytes.BytesReference) CompositeBytesReference(org.elasticsearch.common.bytes.CompositeBytesReference) Version(org.elasticsearch.Version) AbstractRunnable(org.elasticsearch.common.util.concurrent.AbstractRunnable) AbstractLifecycleRunnable(org.elasticsearch.common.util.concurrent.AbstractLifecycleRunnable) ReleasableBytesStreamOutput(org.elasticsearch.common.io.stream.ReleasableBytesStreamOutput) Releasable(org.elasticsearch.common.lease.Releasable) StreamOutput(org.elasticsearch.common.io.stream.StreamOutput) ReleasableBytesStreamOutput(org.elasticsearch.common.io.stream.ReleasableBytesStreamOutput) BytesStreamOutput(org.elasticsearch.common.io.stream.BytesStreamOutput)

Aggregations

Releasable (org.elasticsearch.common.lease.Releasable)38 PlainActionFuture (org.elasticsearch.action.support.PlainActionFuture)7 IndexShard (org.elasticsearch.index.shard.IndexShard)7 ClusterState (org.elasticsearch.cluster.ClusterState)6 IOException (java.io.IOException)5 CountDownLatch (java.util.concurrent.CountDownLatch)5 ElasticsearchException (org.elasticsearch.ElasticsearchException)5 ShardRouting (org.elasticsearch.cluster.routing.ShardRouting)5 TestShardRouting (org.elasticsearch.cluster.routing.TestShardRouting)5 Settings (org.elasticsearch.common.settings.Settings)5 ExecutionException (java.util.concurrent.ExecutionException)4 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)4 BytesReference (org.elasticsearch.common.bytes.BytesReference)4 ArrayList (java.util.ArrayList)3 ActionListener (org.elasticsearch.action.ActionListener)3 ClusterBlockException (org.elasticsearch.cluster.block.ClusterBlockException)3 AbstractRunnable (org.elasticsearch.common.util.concurrent.AbstractRunnable)3 DiscoverySettings (org.elasticsearch.discovery.DiscoverySettings)3 ShardId (org.elasticsearch.index.shard.ShardId)3 List (java.util.List)2