Search in sources :

Example 11 with SegmentPublishResult

use of org.apache.druid.indexing.overlord.SegmentPublishResult in project druid by druid-io.

the class SegmentTransactionalInsertActionTest method testFailTransactionalUpdateDataSourceMetadata.

@Test
public void testFailTransactionalUpdateDataSourceMetadata() throws Exception {
    final Task task = NoopTask.create();
    actionTestKit.getTaskLockbox().add(task);
    acquireTimeChunkLock(TaskLockType.EXCLUSIVE, task, INTERVAL, 5000);
    SegmentPublishResult result = SegmentTransactionalInsertAction.appendAction(ImmutableSet.of(SEGMENT1), new ObjectMetadata(ImmutableList.of(1)), new ObjectMetadata(ImmutableList.of(2))).perform(task, actionTestKit.getTaskActionToolbox());
    Assert.assertEquals(SegmentPublishResult.fail("java.lang.RuntimeException: Aborting transaction!"), result);
}
Also used : SegmentPublishResult(org.apache.druid.indexing.overlord.SegmentPublishResult) NoopTask(org.apache.druid.indexing.common.task.NoopTask) Task(org.apache.druid.indexing.common.task.Task) ObjectMetadata(org.apache.druid.indexing.overlord.ObjectMetadata) Test(org.junit.Test)

Example 12 with SegmentPublishResult

use of org.apache.druid.indexing.overlord.SegmentPublishResult in project druid by druid-io.

the class SegmentTransactionalInsertActionTest method testTransactionalDropSegments.

@Test
public void testTransactionalDropSegments() throws Exception {
    final Task task = NoopTask.create();
    actionTestKit.getTaskLockbox().add(task);
    acquireTimeChunkLock(TaskLockType.EXCLUSIVE, task, INTERVAL, 5000);
    SegmentPublishResult result1 = SegmentTransactionalInsertAction.overwriteAction(null, null, ImmutableSet.of(SEGMENT1)).perform(task, actionTestKit.getTaskActionToolbox());
    Assert.assertEquals(SegmentPublishResult.ok(ImmutableSet.of(SEGMENT1)), result1);
    SegmentPublishResult result2 = SegmentTransactionalInsertAction.overwriteAction(null, ImmutableSet.of(SEGMENT1), ImmutableSet.of(SEGMENT2)).perform(task, actionTestKit.getTaskActionToolbox());
    Assert.assertEquals(SegmentPublishResult.ok(ImmutableSet.of(SEGMENT2)), result2);
    Assertions.assertThat(actionTestKit.getMetadataStorageCoordinator().retrieveUsedSegmentsForInterval(DATA_SOURCE, INTERVAL, Segments.ONLY_VISIBLE)).containsExactlyInAnyOrder(SEGMENT2);
}
Also used : SegmentPublishResult(org.apache.druid.indexing.overlord.SegmentPublishResult) NoopTask(org.apache.druid.indexing.common.task.NoopTask) Task(org.apache.druid.indexing.common.task.Task) Test(org.junit.Test)

Example 13 with SegmentPublishResult

use of org.apache.druid.indexing.overlord.SegmentPublishResult in project druid by druid-io.

the class BaseAppenderatorDriver method publishInBackground.

/**
 * Publish segments in background. The segments should be dropped (in batch ingestion) or pushed (in streaming
 * ingestion) before being published.
 *
 * @param segmentsAndCommitMetadata result of dropping or pushing
 * @param publisher transactional segment publisher
 *
 * @return a future for publishing segments
 */
ListenableFuture<SegmentsAndCommitMetadata> publishInBackground(@Nullable Set<DataSegment> segmentsToBeOverwritten, @Nullable Set<DataSegment> segmentsToBeDropped, SegmentsAndCommitMetadata segmentsAndCommitMetadata, TransactionalSegmentPublisher publisher, java.util.function.Function<Set<DataSegment>, Set<DataSegment>> outputSegmentsAnnotateFunction) {
    if (segmentsAndCommitMetadata.getSegments().isEmpty()) {
        if (!publisher.supportsEmptyPublish()) {
            log.info("Nothing to publish, skipping publish step.");
            final SettableFuture<SegmentsAndCommitMetadata> retVal = SettableFuture.create();
            retVal.set(segmentsAndCommitMetadata);
            return retVal;
        } else {
            // supportsEmptyPublish, but is kept limited for now until further testing.
            if (appenderator.getTotalRowCount() != 0) {
                throw new ISE("Attempting to publish with empty segment set, but total row count was not 0: [%s].", appenderator.getTotalRowCount());
            }
        }
    }
    final Object metadata = segmentsAndCommitMetadata.getCommitMetadata();
    final Object callerMetadata = metadata == null ? null : ((AppenderatorDriverMetadata) metadata).getCallerMetadata();
    return executor.submit(() -> {
        try {
            final ImmutableSet<DataSegment> ourSegments = ImmutableSet.copyOf(segmentsAndCommitMetadata.getSegments());
            final SegmentPublishResult publishResult = publisher.publishSegments(segmentsToBeOverwritten, segmentsToBeDropped, ourSegments, outputSegmentsAnnotateFunction, callerMetadata);
            if (publishResult.isSuccess()) {
                log.info("Published [%s] segments with commit metadata [%s]", segmentsAndCommitMetadata.getSegments().size(), callerMetadata);
                log.infoSegments(segmentsAndCommitMetadata.getSegments(), "Published segments");
            } else {
                // Publishing didn't affirmatively succeed. However, segments with our identifiers may still be active
                // now after all, for two possible reasons:
                // 
                // 1) A replica may have beat us to publishing these segments. In this case we want to delete the
                // segments we pushed (if they had unique paths) to avoid wasting space on deep storage.
                // 2) We may have actually succeeded, but not realized it due to missing the confirmation response
                // from the overlord. In this case we do not want to delete the segments we pushed, since they are
                // now live!
                final Set<SegmentIdWithShardSpec> segmentsIdentifiers = segmentsAndCommitMetadata.getSegments().stream().map(SegmentIdWithShardSpec::fromDataSegment).collect(Collectors.toSet());
                final Set<DataSegment> activeSegments = usedSegmentChecker.findUsedSegments(segmentsIdentifiers);
                if (activeSegments.equals(ourSegments)) {
                    log.info("Could not publish [%s] segments, but checked and found them already published; continuing.", ourSegments.size());
                    log.infoSegments(segmentsAndCommitMetadata.getSegments(), "Could not publish segments");
                    // Clean up pushed segments if they are physically disjoint from the published ones (this means
                    // they were probably pushed by a replica, and with the unique paths option).
                    final boolean physicallyDisjoint = Sets.intersection(activeSegments.stream().map(DataSegment::getLoadSpec).collect(Collectors.toSet()), ourSegments.stream().map(DataSegment::getLoadSpec).collect(Collectors.toSet())).isEmpty();
                    if (physicallyDisjoint) {
                        segmentsAndCommitMetadata.getSegments().forEach(dataSegmentKiller::killQuietly);
                    }
                } else {
                    // Our segments aren't active. Publish failed for some reason. Clean them up and then throw an error.
                    segmentsAndCommitMetadata.getSegments().forEach(dataSegmentKiller::killQuietly);
                    if (publishResult.getErrorMsg() != null) {
                        log.errorSegments(ourSegments, "Failed to publish segments");
                        throw new ISE("Failed to publish segments because of [%s]", publishResult.getErrorMsg());
                    } else {
                        log.errorSegments(ourSegments, "Failed to publish segments");
                        throw new ISE("Failed to publish segments");
                    }
                }
            }
        } catch (Exception e) {
            // Must not remove segments here, we aren't sure if our transaction succeeded or not.
            log.noStackTrace().warn(e, "Failed publish");
            log.warnSegments(segmentsAndCommitMetadata.getSegments(), "Failed publish, not removing segments");
            Throwables.propagateIfPossible(e);
            throw new RuntimeException(e);
        }
        return segmentsAndCommitMetadata;
    });
}
Also used : DataSegment(org.apache.druid.timeline.DataSegment) IOException(java.io.IOException) SegmentPublishResult(org.apache.druid.indexing.overlord.SegmentPublishResult) ISE(org.apache.druid.java.util.common.ISE)

Example 14 with SegmentPublishResult

use of org.apache.druid.indexing.overlord.SegmentPublishResult in project druid by druid-io.

the class IndexerSQLMetadataStorageCoordinator method announceHistoricalSegments.

@Override
public SegmentPublishResult announceHistoricalSegments(final Set<DataSegment> segments, final Set<DataSegment> segmentsToDrop, @Nullable final DataSourceMetadata startMetadata, @Nullable final DataSourceMetadata endMetadata) throws IOException {
    if (segments.isEmpty()) {
        throw new IllegalArgumentException("segment set must not be empty");
    }
    final String dataSource = segments.iterator().next().getDataSource();
    for (DataSegment segment : segments) {
        if (!dataSource.equals(segment.getDataSource())) {
            throw new IllegalArgumentException("segments must all be from the same dataSource");
        }
    }
    if ((startMetadata == null && endMetadata != null) || (startMetadata != null && endMetadata == null)) {
        throw new IllegalArgumentException("start/end metadata pair must be either null or non-null");
    }
    // Find which segments are used (i.e. not overshadowed).
    final Set<DataSegment> usedSegments = new HashSet<>();
    List<TimelineObjectHolder<String, DataSegment>> segmentHolders = VersionedIntervalTimeline.forSegments(segments).lookupWithIncompletePartitions(Intervals.ETERNITY);
    for (TimelineObjectHolder<String, DataSegment> holder : segmentHolders) {
        for (PartitionChunk<DataSegment> chunk : holder.getObject()) {
            usedSegments.add(chunk.getObject());
        }
    }
    final AtomicBoolean definitelyNotUpdated = new AtomicBoolean(false);
    try {
        return connector.retryTransaction(new TransactionCallback<SegmentPublishResult>() {

            @Override
            public SegmentPublishResult inTransaction(final Handle handle, final TransactionStatus transactionStatus) throws Exception {
                // Set definitelyNotUpdated back to false upon retrying.
                definitelyNotUpdated.set(false);
                if (startMetadata != null) {
                    final DataStoreMetadataUpdateResult result = updateDataSourceMetadataWithHandle(handle, dataSource, startMetadata, endMetadata);
                    if (result != DataStoreMetadataUpdateResult.SUCCESS) {
                        // Metadata was definitely not updated.
                        transactionStatus.setRollbackOnly();
                        definitelyNotUpdated.set(true);
                        if (result == DataStoreMetadataUpdateResult.FAILURE) {
                            throw new RuntimeException("Aborting transaction!");
                        } else if (result == DataStoreMetadataUpdateResult.TRY_AGAIN) {
                            throw new RetryTransactionException("Aborting transaction!");
                        }
                    }
                }
                if (segmentsToDrop != null && !segmentsToDrop.isEmpty()) {
                    final DataStoreMetadataUpdateResult result = dropSegmentsWithHandle(handle, segmentsToDrop, dataSource);
                    if (result != DataStoreMetadataUpdateResult.SUCCESS) {
                        // Metadata store was definitely not updated.
                        transactionStatus.setRollbackOnly();
                        definitelyNotUpdated.set(true);
                        if (result == DataStoreMetadataUpdateResult.FAILURE) {
                            throw new RuntimeException("Aborting transaction!");
                        } else if (result == DataStoreMetadataUpdateResult.TRY_AGAIN) {
                            throw new RetryTransactionException("Aborting transaction!");
                        }
                    }
                }
                final Set<DataSegment> inserted = announceHistoricalSegmentBatch(handle, segments, usedSegments);
                return SegmentPublishResult.ok(ImmutableSet.copyOf(inserted));
            }
        }, 3, getSqlMetadataMaxRetry());
    } catch (CallbackFailedException e) {
        if (definitelyNotUpdated.get()) {
            return SegmentPublishResult.fail(e.getMessage());
        } else {
            // Must throw exception if we are not sure if we updated or not.
            throw e;
        }
    }
}
Also used : ResultSet(java.sql.ResultSet) ImmutableSet(com.google.common.collect.ImmutableSet) Set(java.util.Set) HashSet(java.util.HashSet) TransactionStatus(org.skife.jdbi.v2.TransactionStatus) DataSegment(org.apache.druid.timeline.DataSegment) JsonProcessingException(com.fasterxml.jackson.core.JsonProcessingException) IOException(java.io.IOException) CallbackFailedException(org.skife.jdbi.v2.exceptions.CallbackFailedException) Handle(org.skife.jdbi.v2.Handle) CallbackFailedException(org.skife.jdbi.v2.exceptions.CallbackFailedException) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) SegmentPublishResult(org.apache.druid.indexing.overlord.SegmentPublishResult) TimelineObjectHolder(org.apache.druid.timeline.TimelineObjectHolder) HashSet(java.util.HashSet)

Example 15 with SegmentPublishResult

use of org.apache.druid.indexing.overlord.SegmentPublishResult in project druid by druid-io.

the class IndexerSQLMetadataStorageCoordinatorTest method testTransactionalAnnounceFailDbNotNullWantDifferent.

@Test
public void testTransactionalAnnounceFailDbNotNullWantDifferent() throws IOException {
    final SegmentPublishResult result1 = coordinator.announceHistoricalSegments(ImmutableSet.of(defaultSegment), ImmutableSet.of(), new ObjectMetadata(null), new ObjectMetadata(ImmutableMap.of("foo", "baz")));
    Assert.assertEquals(SegmentPublishResult.ok(ImmutableSet.of(defaultSegment)), result1);
    final SegmentPublishResult result2 = coordinator.announceHistoricalSegments(ImmutableSet.of(defaultSegment2), ImmutableSet.of(), new ObjectMetadata(ImmutableMap.of("foo", "qux")), new ObjectMetadata(ImmutableMap.of("foo", "baz")));
    Assert.assertEquals(SegmentPublishResult.fail("java.lang.RuntimeException: Aborting transaction!"), result2);
    // Should only be tried once per call.
    Assert.assertEquals(2, metadataUpdateCounter.get());
}
Also used : SegmentPublishResult(org.apache.druid.indexing.overlord.SegmentPublishResult) ObjectMetadata(org.apache.druid.indexing.overlord.ObjectMetadata) Test(org.junit.Test)

Aggregations

SegmentPublishResult (org.apache.druid.indexing.overlord.SegmentPublishResult)17 Test (org.junit.Test)14 ObjectMetadata (org.apache.druid.indexing.overlord.ObjectMetadata)7 DataSegment (org.apache.druid.timeline.DataSegment)7 NoopTask (org.apache.druid.indexing.common.task.NoopTask)5 Task (org.apache.druid.indexing.common.task.Task)5 IOException (java.io.IOException)3 HashSet (java.util.HashSet)2 Set (java.util.Set)2 LinearShardSpec (org.apache.druid.timeline.partition.LinearShardSpec)2 Handle (org.skife.jdbi.v2.Handle)2 JsonProcessingException (com.fasterxml.jackson.core.JsonProcessingException)1 TypeReference (com.fasterxml.jackson.core.type.TypeReference)1 ObjectMapper (com.fasterxml.jackson.databind.ObjectMapper)1 ImmutableList (com.google.common.collect.ImmutableList)1 ImmutableMap (com.google.common.collect.ImmutableMap)1 ImmutableSet (com.google.common.collect.ImmutableSet)1 Iterables (com.google.common.collect.Iterables)1 ListenableFuture (com.google.common.util.concurrent.ListenableFuture)1 ListeningExecutorService (com.google.common.util.concurrent.ListeningExecutorService)1