This is an automated email from the ASF dual-hosted git repository.
amatya pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/druid.git
The following commit(s) were added to refs/heads/master by this push:
new e16096735b Fix 404 when segment is used but not in the Coordinator
snapshot (#14762)
e16096735b is described below
commit e16096735bc2cf36cde7dfefb9bd086100a3f9a4
Author: AmatyaAvadhanula <[email protected]>
AuthorDate: Mon Aug 14 13:20:43 2023 +0530
Fix 404 when segment is used but not in the Coordinator snapshot (#14762)
* Fix 404 when used segment has not been updated in the Coordinator snapshot
* Add unit test
---
.../TestIndexerMetadataStorageCoordinator.java | 6 ++++
.../IndexerMetadataStorageCoordinator.java | 10 ++++++
.../IndexerSQLMetadataStorageCoordinator.java | 12 ++++++++
.../druid/metadata/SqlSegmentsMetadataQuery.java | 23 ++++++++++++++
.../apache/druid/server/http/MetadataResource.java | 5 +++
.../druid/server/http/MetadataResourceTest.java | 36 ++++++++++++++++++++--
6 files changed, 90 insertions(+), 2 deletions(-)
diff --git
a/indexing-service/src/test/java/org/apache/druid/indexing/test/TestIndexerMetadataStorageCoordinator.java
b/indexing-service/src/test/java/org/apache/druid/indexing/test/TestIndexerMetadataStorageCoordinator.java
index 66af0a9730..0606889b7f 100644
---
a/indexing-service/src/test/java/org/apache/druid/indexing/test/TestIndexerMetadataStorageCoordinator.java
+++
b/indexing-service/src/test/java/org/apache/druid/indexing/test/TestIndexerMetadataStorageCoordinator.java
@@ -229,6 +229,12 @@ public class TestIndexerMetadataStorageCoordinator
implements IndexerMetadataSto
throw new UnsupportedOperationException();
}
+ @Override
+ public DataSegment retrieveUsedSegmentForId(final String id)
+ {
+ return null;
+ }
+
public Set<DataSegment> getPublished()
{
return ImmutableSet.copyOf(published);
diff --git
a/server/src/main/java/org/apache/druid/indexing/overlord/IndexerMetadataStorageCoordinator.java
b/server/src/main/java/org/apache/druid/indexing/overlord/IndexerMetadataStorageCoordinator.java
index 3d8f4b8586..589b60f027 100644
---
a/server/src/main/java/org/apache/druid/indexing/overlord/IndexerMetadataStorageCoordinator.java
+++
b/server/src/main/java/org/apache/druid/indexing/overlord/IndexerMetadataStorageCoordinator.java
@@ -352,4 +352,14 @@ public interface IndexerMetadataStorageCoordinator
void updateSegmentMetadata(Set<DataSegment> segments);
void deleteSegments(Set<DataSegment> segments);
+
+ /**
+ * Retrieve the segment for a given id from the metadata store. Return null
if no such used segment exists
+ *
+ * @param id The segment id
+ *
+ * @return DataSegment corresponding to given id
+ */
+ DataSegment retrieveUsedSegmentForId(String id);
+
}
diff --git
a/server/src/main/java/org/apache/druid/metadata/IndexerSQLMetadataStorageCoordinator.java
b/server/src/main/java/org/apache/druid/metadata/IndexerSQLMetadataStorageCoordinator.java
index 6c4d523133..bbf7a7f7bf 100644
---
a/server/src/main/java/org/apache/druid/metadata/IndexerSQLMetadataStorageCoordinator.java
+++
b/server/src/main/java/org/apache/druid/metadata/IndexerSQLMetadataStorageCoordinator.java
@@ -1883,6 +1883,18 @@ public class IndexerSQLMetadataStorageCoordinator
implements IndexerMetadataStor
);
}
+ @Override
+ public DataSegment retrieveUsedSegmentForId(final String id)
+ {
+ return connector.retryTransaction(
+ (handle, status) ->
+ SqlSegmentsMetadataQuery.forHandle(handle, connector, dbTables,
jsonMapper)
+ .retrieveUsedSegmentForId(id),
+ 3,
+ SQLMetadataConnector.DEFAULT_MAX_TRIES
+ );
+ }
+
private static class PendingSegmentsRecord
{
private final String sequenceName;
diff --git
a/server/src/main/java/org/apache/druid/metadata/SqlSegmentsMetadataQuery.java
b/server/src/main/java/org/apache/druid/metadata/SqlSegmentsMetadataQuery.java
index 45896a865e..b35116584f 100644
---
a/server/src/main/java/org/apache/druid/metadata/SqlSegmentsMetadataQuery.java
+++
b/server/src/main/java/org/apache/druid/metadata/SqlSegmentsMetadataQuery.java
@@ -212,6 +212,29 @@ public class SqlSegmentsMetadataQuery
}
}
+ /**
+ * Retrieve the used segment for a given id if it exists in the metadata
store and null otherwise
+ */
+ public DataSegment retrieveUsedSegmentForId(String id)
+ {
+
+ final String query = "SELECT payload FROM %s WHERE used = true AND id =
:id";
+
+ final Query<Map<String, Object>> sql = handle
+ .createQuery(StringUtils.format(query, dbTables.getSegmentsTable()))
+ .bind("id", id);
+
+ final ResultIterator<DataSegment> resultIterator =
+ sql.map((index, r, ctx) -> JacksonUtils.readValue(jsonMapper,
r.getBytes(1), DataSegment.class))
+ .iterator();
+
+ if (resultIterator.hasNext()) {
+ return resultIterator.next();
+ }
+
+ return null;
+ }
+
private CloseableIterator<DataSegment> retrieveSegments(
final String dataSource,
final Collection<Interval> intervals,
diff --git
a/server/src/main/java/org/apache/druid/server/http/MetadataResource.java
b/server/src/main/java/org/apache/druid/server/http/MetadataResource.java
index 6cdf9c546a..4f9631c1cf 100644
--- a/server/src/main/java/org/apache/druid/server/http/MetadataResource.java
+++ b/server/src/main/java/org/apache/druid/server/http/MetadataResource.java
@@ -295,6 +295,11 @@ public class MetadataResource
return Response.status(Response.Status.OK).entity(segment).build();
}
}
+ // fallback to db
+ DataSegment segment =
metadataStorageCoordinator.retrieveUsedSegmentForId(segmentId);
+ if (segment != null) {
+ return Response.status(Response.Status.OK).entity(segment).build();
+ }
return Response.status(Response.Status.NOT_FOUND).build();
}
}
diff --git
a/server/src/test/java/org/apache/druid/server/http/MetadataResourceTest.java
b/server/src/test/java/org/apache/druid/server/http/MetadataResourceTest.java
index e59e149d8c..d5ab6aaaa1 100644
---
a/server/src/test/java/org/apache/druid/server/http/MetadataResourceTest.java
+++
b/server/src/test/java/org/apache/druid/server/http/MetadataResourceTest.java
@@ -53,7 +53,7 @@ public class MetadataResourceTest
private final DataSegment[] segments =
CreateDataSegments.ofDatasource(DATASOURCE1)
- .forIntervals(2, Granularities.DAY)
+ .forIntervals(3, Granularities.DAY)
.withNumPartitions(2)
.eachOfSizeInMb(500)
.toArray(new DataSegment[0]);
@@ -77,6 +77,9 @@ public class MetadataResourceTest
.when(segmentsMetadataManager).getSnapshotOfDataSourcesWithAllUsedSegments();
Mockito.doReturn(ImmutableList.of(druidDataSource1))
.when(dataSourcesSnapshot).getDataSourcesWithAllUsedSegments();
+ Mockito.doReturn(druidDataSource1)
+ .when(segmentsMetadataManager)
+ .getImmutableDataSourceWithUsedSegments(DATASOURCE1);
DruidCoordinator coordinator = Mockito.mock(DruidCoordinator.class);
Mockito.doReturn(2).when(coordinator).getReplicationFactor(segments[0].getId());
@@ -86,9 +89,17 @@ public class MetadataResourceTest
Mockito.doReturn(ImmutableSet.of(segments[3]))
.when(dataSourcesSnapshot).getOvershadowedSegments();
+ IndexerMetadataStorageCoordinator storageCoordinator =
Mockito.mock(IndexerMetadataStorageCoordinator.class);
+ Mockito.doReturn(segments[4])
+ .when(storageCoordinator)
+ .retrieveUsedSegmentForId(segments[4].getId().toString());
+ Mockito.doReturn(null)
+ .when(storageCoordinator)
+ .retrieveUsedSegmentForId(segments[5].getId().toString());
+
metadataResource = new MetadataResource(
segmentsMetadataManager,
- Mockito.mock(IndexerMetadataStorageCoordinator.class),
+ storageCoordinator,
AuthTestUtils.TEST_AUTHORIZER_MAPPER,
coordinator
);
@@ -108,6 +119,27 @@ public class MetadataResourceTest
Assert.assertEquals(new SegmentStatusInCluster(segments[3], true, 0),
resultList.get(3));
}
+ @Test
+ public void testGetUsedSegment()
+ {
+ // Available in snapshot
+ Assert.assertEquals(
+ segments[0],
+ metadataResource.getUsedSegment(segments[0].getDataSource(),
segments[0].getId().toString()).getEntity()
+ );
+
+ // Unavailable in snapshot, but available in metadata
+ Assert.assertEquals(
+ segments[4],
+ metadataResource.getUsedSegment(segments[4].getDataSource(),
segments[4].getId().toString()).getEntity()
+ );
+
+ // Unavailable in both snapshot and metadata
+ Assert.assertNull(
+ metadataResource.getUsedSegment(segments[5].getDataSource(),
segments[5].getId().toString()).getEntity()
+ );
+ }
+
private List<SegmentStatusInCluster> extractSegmentStatusList(Response
response)
{
return Lists.newArrayList(
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]