Search in sources :

Example 6 with Document

use of com.microsoft.azure.cosmosdb.Document in project ambry by linkedin.

the class CosmosDataAccessorTest method testQueryChangeFeedNormal.

/**
 * Test change feed query.
 */
@Test
public void testQueryChangeFeedNormal() throws Exception {
    Observable<FeedResponse<Document>> mockResponse = mock(Observable.class);
    List<Document> docList = Collections.singletonList(AzureTestUtils.createDocumentFromCloudBlobMetadata(blobMetadata));
    mockObservableForChangeFeedQuery(docList, mockResponse);
    when(mockumentClient.queryDocumentChangeFeed(anyString(), any(ChangeFeedOptions.class))).thenReturn(mockResponse);
    // test with non null requestContinuationToken
    List<CloudBlobMetadata> metadataList = doQueryChangeFeed("test");
    assertEquals("Expected single entry", 1, metadataList.size());
    CloudBlobMetadata outputMetadata = metadataList.get(0);
    assertEquals("Returned metadata does not match original", blobMetadata, outputMetadata);
    assertEquals(1, azureMetrics.changeFeedQueryCount.getCount());
    assertEquals(0, azureMetrics.changeFeedQueryFailureCount.getCount());
    // test with a null continuation token
    metadataList = doQueryChangeFeed(null);
    assertEquals("Expected single entry", 1, metadataList.size());
    outputMetadata = metadataList.get(0);
    assertEquals("Returned metadata does not match original", blobMetadata, outputMetadata);
    assertEquals(2, azureMetrics.changeFeedQueryCount.getCount());
    assertEquals(0, azureMetrics.changeFeedQueryFailureCount.getCount());
    // test when queryChangeFeed throws exception
    when(mockumentClient.queryDocumentChangeFeed(anyString(), any(ChangeFeedOptions.class))).thenThrow(new RuntimeException("mock exception", new DocumentClientException(404)));
    try {
        doQueryChangeFeed(null);
    } catch (DocumentClientException e) {
    }
    assertEquals(3, azureMetrics.changeFeedQueryCount.getCount());
    assertEquals(1, azureMetrics.changeFeedQueryFailureCount.getCount());
}
Also used : CloudBlobMetadata(com.github.ambry.cloud.CloudBlobMetadata) FeedResponse(com.microsoft.azure.cosmosdb.FeedResponse) ChangeFeedOptions(com.microsoft.azure.cosmosdb.ChangeFeedOptions) Document(com.microsoft.azure.cosmosdb.Document) DocumentClientException(com.microsoft.azure.cosmosdb.DocumentClientException) Test(org.junit.Test)

Example 7 with Document

use of com.microsoft.azure.cosmosdb.Document in project ambry by linkedin.

the class CosmosDataAccessor method getDeadBlobs.

/**
 * Get the list of blobs in the specified partition that have been deleted or expired for at least the
 * configured retention period.
 * @param partitionPath the partition to query.
 * @param fieldName the field name to query on. Allowed values are {@link CloudBlobMetadata#FIELD_DELETION_TIME} and
 *                  {@link CloudBlobMetadata#FIELD_EXPIRATION_TIME}.
 * @param startTime the start of the query time range.
 * @param endTime the end of the query time range.
 * @param maxEntries the max number of metadata records to return.
 * @return a List of {@link CloudBlobMetadata} referencing the dead blobs found.
 * @throws DocumentClientException
 */
List<CloudBlobMetadata> getDeadBlobs(String partitionPath, String fieldName, long startTime, long endTime, int maxEntries) throws DocumentClientException {
    String deadBlobsQuery;
    if (fieldName.equals(CloudBlobMetadata.FIELD_DELETION_TIME)) {
        deadBlobsQuery = DELETED_BLOBS_QUERY;
    } else if (fieldName.equals(CloudBlobMetadata.FIELD_EXPIRATION_TIME)) {
        deadBlobsQuery = EXPIRED_BLOBS_QUERY;
    } else {
        throw new IllegalArgumentException("Invalid field: " + fieldName);
    }
    SqlQuerySpec querySpec = new SqlQuerySpec(deadBlobsQuery, new SqlParameterCollection(new SqlParameter(LIMIT_PARAM, maxEntries), new SqlParameter(START_TIME_PARAM, startTime), new SqlParameter(END_TIME_PARAM, endTime)));
    FeedOptions feedOptions = new FeedOptions();
    feedOptions.setMaxItemCount(maxEntries);
    feedOptions.setResponseContinuationTokenLimitInKb(continuationTokenLimitKb);
    feedOptions.setPartitionKey(new PartitionKey(partitionPath));
    try {
        Iterator<FeedResponse<Document>> iterator = executeCosmosQuery(partitionPath, querySpec, feedOptions, azureMetrics.deadBlobsQueryTime).getIterator();
        List<CloudBlobMetadata> deadBlobsList = new ArrayList<>();
        double requestCharge = 0.0;
        while (iterator.hasNext()) {
            FeedResponse<Document> response = iterator.next();
            requestCharge += response.getRequestCharge();
            response.getResults().iterator().forEachRemaining(doc -> deadBlobsList.add(createMetadataFromDocument(doc)));
        }
        if (requestCharge >= requestChargeThreshold) {
            logger.info("Dead blobs query partition {} endTime {} request charge {} for {} records", partitionPath, new Date(endTime), requestCharge, deadBlobsList.size());
        }
        return deadBlobsList;
    } catch (RuntimeException rex) {
        if (rex.getCause() instanceof DocumentClientException) {
            logger.warn("Dead blobs query {} partition {} got {}", deadBlobsQuery, partitionPath, ((DocumentClientException) rex.getCause()).getStatusCode());
            throw (DocumentClientException) rex.getCause();
        }
        throw rex;
    }
}
Also used : SqlParameter(com.microsoft.azure.cosmosdb.SqlParameter) CloudBlobMetadata(com.github.ambry.cloud.CloudBlobMetadata) ArrayList(java.util.ArrayList) FeedResponse(com.microsoft.azure.cosmosdb.FeedResponse) Document(com.microsoft.azure.cosmosdb.Document) Date(java.util.Date) SqlParameterCollection(com.microsoft.azure.cosmosdb.SqlParameterCollection) SqlQuerySpec(com.microsoft.azure.cosmosdb.SqlQuerySpec) ChangeFeedOptions(com.microsoft.azure.cosmosdb.ChangeFeedOptions) FeedOptions(com.microsoft.azure.cosmosdb.FeedOptions) PartitionKey(com.microsoft.azure.cosmosdb.PartitionKey) DocumentClientException(com.microsoft.azure.cosmosdb.DocumentClientException)

Example 8 with Document

use of com.microsoft.azure.cosmosdb.Document in project ambry by linkedin.

the class CosmosDataAccessor method getMetadataOrNull.

/**
 * Get the metadata record for a single blob.
 * @param blobId the blob to read.
 * @return the {@link CloudBlobMetadata} for the blob if it is found, otherwise null.
 * @throws DocumentClientException on any other error.
 */
CloudBlobMetadata getMetadataOrNull(BlobId blobId) throws DocumentClientException {
    String docLink = getDocumentLink(blobId.getID());
    RequestOptions options = getRequestOptions(blobId.getPartition().toPathString());
    try {
        ResourceResponse<Document> readResponse = executeCosmosAction(() -> asyncDocumentClient.readDocument(docLink, options).toBlocking().single(), azureMetrics.documentReadTime);
        return createMetadataFromDocument(readResponse.getResource());
    } catch (DocumentClientException dex) {
        if (dex.getStatusCode() == HttpConstants.StatusCodes.NOTFOUND) {
            return null;
        } else {
            throw dex;
        }
    }
}
Also used : RequestOptions(com.microsoft.azure.cosmosdb.RequestOptions) Document(com.microsoft.azure.cosmosdb.Document) DocumentClientException(com.microsoft.azure.cosmosdb.DocumentClientException)

Example 9 with Document

use of com.microsoft.azure.cosmosdb.Document in project ambry by linkedin.

the class CosmosDataAccessor method getDeprecatedContainers.

/**
 * Fetch a {@link Set} of {@link CosmosContainerDeletionEntry} objects from cosmos db that are not marked as deleted.
 * @param maxEntries Max number of entries to fetch on one query.
 * @return {@link Set} of {@link CosmosContainerDeletionEntry} objects.
 * @throws DocumentClientException in case of any error.
 */
public Set<CosmosContainerDeletionEntry> getDeprecatedContainers(int maxEntries) throws DocumentClientException {
    SqlQuerySpec querySpec = new SqlQuerySpec(DEPRECATED_CONTAINERS_QUERY, new SqlParameterCollection(new SqlParameter(LIMIT_PARAM, maxEntries)));
    Timer timer = new Timer();
    Set<CosmosContainerDeletionEntry> containerDeletionEntries = new HashSet<>();
    try {
        Iterator<FeedResponse<Document>> iterator = executeCosmosQuery(cosmosDeletedContainerCollectionLink, null, querySpec, new FeedOptions(), timer).getIterator();
        while (iterator.hasNext()) {
            FeedResponse<Document> response = iterator.next();
            response.getResults().iterator().forEachRemaining(doc -> containerDeletionEntries.add(CosmosContainerDeletionEntry.fromJson(new JSONObject(doc.toJson()))));
        }
    } catch (RuntimeException rex) {
        if (rex.getCause() instanceof DocumentClientException) {
            logger.warn("Get deprecated containers query {} got {}", querySpec.getQueryText(), ((DocumentClientException) rex.getCause()).getStatusCode());
            throw (DocumentClientException) rex.getCause();
        }
        throw rex;
    }
    return containerDeletionEntries;
}
Also used : SqlParameter(com.microsoft.azure.cosmosdb.SqlParameter) FeedResponse(com.microsoft.azure.cosmosdb.FeedResponse) Document(com.microsoft.azure.cosmosdb.Document) SqlParameterCollection(com.microsoft.azure.cosmosdb.SqlParameterCollection) SqlQuerySpec(com.microsoft.azure.cosmosdb.SqlQuerySpec) Timer(com.codahale.metrics.Timer) JSONObject(org.json.JSONObject) ChangeFeedOptions(com.microsoft.azure.cosmosdb.ChangeFeedOptions) FeedOptions(com.microsoft.azure.cosmosdb.FeedOptions) HashSet(java.util.HashSet) DocumentClientException(com.microsoft.azure.cosmosdb.DocumentClientException)

Example 10 with Document

use of com.microsoft.azure.cosmosdb.Document in project ambry by linkedin.

the class CosmosDataAccessor method updateContainerDeletionEntry.

/**
 * Update the container deletion entry document in the CosmosDB collection.
 * @param containerId the container id for which document is replaced.
 * @param accountId the account id for which document is replaced.
 * @param updateFields {@link BiConsumer} object to use as callback to update the required fields.
 * @return the {@link ResourceResponse} returned by the operation, if successful.
 * Returns {@Null} if the field already has the specified value.
 * @throws DocumentClientException if the record was not found or if the operation failed.
 */
ResourceResponse<Document> updateContainerDeletionEntry(short containerId, short accountId, BiConsumer<Document, AtomicBoolean> updateFields) throws DocumentClientException {
    // Read the existing record
    String id = CosmosContainerDeletionEntry.generateContainerDeletionEntryId(accountId, containerId);
    String docLink = getContainerDeletionEntryDocumentLink(id);
    RequestOptions options = getRequestOptions(id);
    ResourceResponse<Document> readResponse = executeCosmosAction(() -> asyncDocumentClient.readDocument(docLink, options).toBlocking().single(), azureMetrics.continerDeletionEntryReadTime);
    Document doc = readResponse.getResource();
    AtomicBoolean fieldsChanged = new AtomicBoolean(false);
    updateFields.accept(doc, fieldsChanged);
    if (!fieldsChanged.get()) {
        logger.debug("No change in value for container deletion entry {}", doc.toJson());
        return null;
    }
    // For testing conflict handling
    if (updateCallback != null) {
        try {
            updateCallback.call();
        } catch (Exception ex) {
            logger.error("Error in update callback", ex);
        }
    }
    // Set condition to ensure we don't clobber a concurrent update
    AccessCondition accessCondition = new AccessCondition();
    accessCondition.setCondition(doc.getETag());
    options.setAccessCondition(accessCondition);
    try {
        return executeCosmosAction(() -> asyncDocumentClient.replaceDocument(doc, options).toBlocking().single(), azureMetrics.documentUpdateTime);
    } catch (DocumentClientException e) {
        if (e.getStatusCode() == HttpConstants.StatusCodes.PRECONDITION_FAILED) {
            azureMetrics.blobUpdateConflictCount.inc();
        }
        throw e;
    }
}
Also used : AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) RequestOptions(com.microsoft.azure.cosmosdb.RequestOptions) AccessCondition(com.microsoft.azure.cosmosdb.AccessCondition) Document(com.microsoft.azure.cosmosdb.Document) DocumentClientException(com.microsoft.azure.cosmosdb.DocumentClientException) CloudStorageException(com.github.ambry.cloud.CloudStorageException) DocumentClientException(com.microsoft.azure.cosmosdb.DocumentClientException)

Aggregations

Document (com.microsoft.azure.cosmosdb.Document)23 FeedResponse (com.microsoft.azure.cosmosdb.FeedResponse)15 CloudBlobMetadata (com.github.ambry.cloud.CloudBlobMetadata)14 FeedOptions (com.microsoft.azure.cosmosdb.FeedOptions)14 SqlQuerySpec (com.microsoft.azure.cosmosdb.SqlQuerySpec)13 DocumentClientException (com.microsoft.azure.cosmosdb.DocumentClientException)10 ArrayList (java.util.ArrayList)10 BlobId (com.github.ambry.commons.BlobId)9 ChangeFeedOptions (com.microsoft.azure.cosmosdb.ChangeFeedOptions)9 PartitionKey (com.microsoft.azure.cosmosdb.PartitionKey)7 RequestOptions (com.microsoft.azure.cosmosdb.RequestOptions)7 SqlParameter (com.microsoft.azure.cosmosdb.SqlParameter)5 SqlParameterCollection (com.microsoft.azure.cosmosdb.SqlParameterCollection)5 CloudStorageException (com.github.ambry.cloud.CloudStorageException)4 VcrMetrics (com.github.ambry.cloud.VcrMetrics)4 ResourceResponse (com.microsoft.azure.cosmosdb.ResourceResponse)4 StoredProcedureResponse (com.microsoft.azure.cosmosdb.StoredProcedureResponse)4 AsyncDocumentClient (com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient)4 HashSet (java.util.HashSet)4 Test (org.junit.Test)4