diff options
Diffstat (limited to 'vespaclient-container-plugin/src')
2 files changed, 28 insertions, 8 deletions
diff --git a/vespaclient-container-plugin/src/main/java/com/yahoo/document/restapi/resource/DocumentV1ApiHandler.java b/vespaclient-container-plugin/src/main/java/com/yahoo/document/restapi/resource/DocumentV1ApiHandler.java index b483d6977d6..4bd78d2030f 100644 --- a/vespaclient-container-plugin/src/main/java/com/yahoo/document/restapi/resource/DocumentV1ApiHandler.java +++ b/vespaclient-container-plugin/src/main/java/com/yahoo/document/restapi/resource/DocumentV1ApiHandler.java @@ -1397,6 +1397,7 @@ public class DocumentV1ApiHandler extends AbstractRequestHandler { Phaser phaser = new Phaser(2); // Synchronize this thread (dispatch) with the visitor callback thread. AtomicReference<String> error = new AtomicReference<>(); // Set if error occurs during processing of visited documents. callback.onStart(response, fullyApplied); + final AtomicLong locallyReceivedDocCount = new AtomicLong(0); VisitorControlHandler controller = new VisitorControlHandler() { final ScheduledFuture<?> abort = streaming ? visitDispatcher.schedule(this::abort, visitTimeout(request), MILLISECONDS) : null; final AtomicReference<VisitorSession> session = new AtomicReference<>(); @@ -1410,7 +1411,10 @@ public class DocumentV1ApiHandler extends AbstractRequestHandler { try (response) { callback.onEnd(response); - response.writeDocumentCount(getVisitorStatistics() == null ? 0 : getVisitorStatistics().getDocumentsVisited()); + // Locally tracked document count is only correct if we have a local data handler. + // Otherwise, we have to report the statistics received transitively from the content nodes. + long statsDocCount = (getVisitorStatistics() != null ? getVisitorStatistics().getDocumentsVisited() : 0); + response.writeDocumentCount(parameters.getLocalDataHandler() != null ? locallyReceivedDocCount.get() : statsDocCount); if (session.get() != null) response.writeTrace(session.get().getTrace()); @@ -1456,6 +1460,7 @@ public class DocumentV1ApiHandler extends AbstractRequestHandler { if (m instanceof PutDocumentMessage put) document = put.getDocumentPut().getDocument(); else if (parameters.visitRemoves() && m instanceof RemoveDocumentMessage remove) removeId = remove.getDocumentId(); else throw new UnsupportedOperationException("Got unsupported message type: " + m.getClass().getName()); + locallyReceivedDocCount.getAndAdd(1); callback.onDocument(response, document, removeId, @@ -1616,8 +1621,8 @@ public class DocumentV1ApiHandler extends AbstractRequestHandler { static String resolveBucket(StorageCluster cluster, Optional<String> documentType, List<String> bucketSpaces, Optional<String> bucketSpace) { return documentType.map(type -> cluster.bucketOf(type) - .orElseThrow(() -> new IllegalArgumentException("Document type '" + type + "' in cluster '" + cluster.name() + - "' is not mapped to a known bucket space"))) + .orElseThrow(() -> new IllegalArgumentException("There is no document type '" + type + "' in cluster '" + cluster.name() + + "', only '" + String.join("', '", cluster.documentBuckets.keySet()) + "'"))) .or(() -> bucketSpace.map(space -> { if ( ! bucketSpaces.contains(space)) throw new IllegalArgumentException("Bucket space '" + space + "' is not a known bucket space; expected one of " + diff --git a/vespaclient-container-plugin/src/test/java/com/yahoo/document/restapi/resource/DocumentV1ApiTest.java b/vespaclient-container-plugin/src/test/java/com/yahoo/document/restapi/resource/DocumentV1ApiTest.java index 58cf34712aa..2d3198cc7f4 100644 --- a/vespaclient-container-plugin/src/test/java/com/yahoo/document/restapi/resource/DocumentV1ApiTest.java +++ b/vespaclient-container-plugin/src/test/java/com/yahoo/document/restapi/resource/DocumentV1ApiTest.java @@ -185,8 +185,18 @@ public class DocumentV1ApiTest { StorageCluster cluster = DocumentV1ApiHandler.resolveCluster(Optional.of("content"), clusters); assertEquals(FixedBucketSpaces.defaultSpace(), DocumentV1ApiHandler.resolveBucket(cluster, Optional.of("music"), List.of(), Optional.empty())); + assertEquals(FixedBucketSpaces.defaultSpace(), + DocumentV1ApiHandler.resolveBucket(cluster, Optional.empty(), List.of(), Optional.empty())); assertEquals(FixedBucketSpaces.globalSpace(), DocumentV1ApiHandler.resolveBucket(cluster, Optional.empty(), List.of(FixedBucketSpaces.globalSpace()), Optional.of("global"))); + try { + DocumentV1ApiHandler.resolveBucket(cluster, Optional.of("musicc"), List.of(), Optional.empty()); + fail("should fail with unknown document type"); + } + catch (IllegalArgumentException e) { + assertEquals("There is no document type 'musicc' in cluster 'content', only 'music'", + e.getMessage()); + } } @Test @@ -290,7 +300,7 @@ public class DocumentV1ApiTest { parameters.getLocalDataHandler().onMessage(new RemoveDocumentMessage(new DocumentId("id:space:music::t-square-truth")), tokens.get(3)); VisitorStatistics statistics = new VisitorStatistics(); statistics.setBucketsVisited(1); - statistics.setDocumentsVisited(3); + statistics.setDocumentsVisited(123); // Ignored in favor of tracking actually emitted entries parameters.getControlHandler().onVisitorStatistics(statistics); parameters.getControlHandler().onDone(VisitorControlHandler.CompletionCode.TIMEOUT, "timeout is OK"); }); @@ -323,7 +333,7 @@ public class DocumentV1ApiTest { "remove": "id:space:music::t-square-truth" } ], - "documentCount": 3, + "documentCount": 4, "trace": [ { "message": "Tracy Chapman" }, { @@ -441,13 +451,18 @@ public class DocumentV1ApiTest { assertEquals("[Content:cluster=content]", parameters.getRemoteDataHandler()); assertEquals("[document]", parameters.fieldSet()); assertEquals(60_000L, parameters.getSessionTimeoutMs()); + VisitorStatistics statistics = new VisitorStatistics(); + statistics.setBucketsVisited(1); + statistics.setDocumentsVisited(2); + // Visiting with remote data handlers should report the remotely aggregated statistics + parameters.getControlHandler().onVisitorStatistics(statistics); parameters.getControlHandler().onDone(VisitorControlHandler.CompletionCode.SUCCESS, "We made it!"); }); response = driver.sendRequest("http://localhost/document/v1/space/music/docid?destinationCluster=content&selection=true&cluster=content&timeout=60", POST); assertSameJson(""" { "pathId": "/document/v1/space/music/docid", - "documentCount": 0 + "documentCount": 2 }""", response.readAll()); assertEquals(200, response.getStatus()); @@ -488,7 +503,7 @@ public class DocumentV1ApiTest { assertSameJson(""" { "pathId": "/document/v1/space/music/docid", - "documentCount": 0 + "documentCount": 1 }""", response.readAll()); assertEquals(200, response.getStatus()); @@ -542,7 +557,7 @@ public class DocumentV1ApiTest { assertSameJson(""" { "pathId": "/document/v1/space/music/docid", - "documentCount": 0, + "documentCount": 1, "message": "boom" }""", response.readAll()); |