This is an automated email from the ASF dual-hosted git repository. miroslav pushed a commit to branch issue/OAK-10573_azure_write_timeout in repository https://gitbox.apache.org/repos/asf/jackrabbit-oak.git
commit f0665d84507bac6fa42c9ab41419be33907e961e Author: Miroslav Smiljanic <[email protected]> AuthorDate: Wed Nov 29 17:57:23 2023 +0100 OAK-10573 request options optimised for write operations --- .../oak/segment/azure/AzureJournalFile.java | 15 ++++-- .../oak/segment/azure/AzurePersistence.java | 22 +------- .../segment/azure/AzureSegmentArchiveWriter.java | 13 +++-- .../segment/azure/util/AzureRequestOptions.java | 63 ++++++++++++++++++++++ 4 files changed, 85 insertions(+), 28 deletions(-) diff --git a/oak-segment-azure/src/main/java/org/apache/jackrabbit/oak/segment/azure/AzureJournalFile.java b/oak-segment-azure/src/main/java/org/apache/jackrabbit/oak/segment/azure/AzureJournalFile.java index b468e42b44..76b52de113 100644 --- a/oak-segment-azure/src/main/java/org/apache/jackrabbit/oak/segment/azure/AzureJournalFile.java +++ b/oak-segment-azure/src/main/java/org/apache/jackrabbit/oak/segment/azure/AzureJournalFile.java @@ -22,6 +22,9 @@ import com.microsoft.azure.storage.blob.CloudAppendBlob; import com.microsoft.azure.storage.blob.CloudBlob; import com.microsoft.azure.storage.blob.CloudBlobDirectory; import com.microsoft.azure.storage.blob.ListBlobItem; +import com.microsoft.azure.storage.blob.DeleteSnapshotsOption; +import com.microsoft.azure.storage.blob.BlobRequestOptions; +import org.apache.jackrabbit.oak.segment.azure.util.AzureRequestOptions; import org.apache.jackrabbit.oak.segment.azure.util.CaseInsensitiveKeysMapAccess; import org.apache.jackrabbit.oak.segment.remote.WriteAccessController; import org.apache.jackrabbit.oak.segment.spi.persistence.JournalFile; @@ -162,7 +165,11 @@ public class AzureJournalFile implements JournalFile { private int lineCount; + private final BlobRequestOptions writeOptimisedBlobRequestOptions; + public AzureJournalWriter() throws IOException { + writeOptimisedBlobRequestOptions = AzureRequestOptions.optimiseForWriteOperations(directory.getServiceClient().getDefaultRequestOptions()); + List<CloudAppendBlob> blobs = getJournalBlobs(); if (blobs.isEmpty()) { try { @@ -190,7 +197,7 @@ public class AzureJournalFile implements JournalFile { writeAccessController.checkWritingAllowed(); for (CloudAppendBlob cloudAppendBlob : getJournalBlobs()) { - cloudAppendBlob.delete(); + cloudAppendBlob.delete(DeleteSnapshotsOption.NONE, null, writeOptimisedBlobRequestOptions, null); } createNextFile(0); @@ -229,11 +236,11 @@ public class AzureJournalFile implements JournalFile { text.append(line).append("\n"); } try { - currentBlob.appendText(text.toString()); + currentBlob.appendText(text.toString(), null, null, writeOptimisedBlobRequestOptions, null); currentBlob.getMetadata().put("lastEntry", entries.get(entries.size() - 1)); lineCount += entries.size(); currentBlob.getMetadata().put("lineCount", Integer.toString(lineCount)); - currentBlob.uploadMetadata(); + currentBlob.uploadMetadata(null, writeOptimisedBlobRequestOptions, null); } catch (StorageException e) { throw new IOException(e); } @@ -243,7 +250,7 @@ public class AzureJournalFile implements JournalFile { private void createNextFile(int suffix) throws IOException { try { currentBlob = directory.getAppendBlobReference(getJournalFileName(suffix + 1)); - currentBlob.createOrReplace(); + currentBlob.createOrReplace(null, writeOptimisedBlobRequestOptions, null); lineCount = 0; } catch (URISyntaxException | StorageException e) { throw new IOException(e); diff --git a/oak-segment-azure/src/main/java/org/apache/jackrabbit/oak/segment/azure/AzurePersistence.java b/oak-segment-azure/src/main/java/org/apache/jackrabbit/oak/segment/azure/AzurePersistence.java index eed07004e5..392a352915 100644 --- a/oak-segment-azure/src/main/java/org/apache/jackrabbit/oak/segment/azure/AzurePersistence.java +++ b/oak-segment-azure/src/main/java/org/apache/jackrabbit/oak/segment/azure/AzurePersistence.java @@ -34,6 +34,7 @@ import com.microsoft.azure.storage.blob.CloudAppendBlob; import com.microsoft.azure.storage.blob.CloudBlobDirectory; import com.microsoft.azure.storage.blob.CloudBlockBlob; import com.microsoft.azure.storage.blob.ListBlobItem; +import org.apache.jackrabbit.oak.segment.azure.util.AzureRequestOptions; import org.apache.jackrabbit.oak.segment.remote.WriteAccessController; import org.apache.jackrabbit.oak.segment.spi.monitor.FileStoreMonitor; import org.apache.jackrabbit.oak.segment.spi.monitor.IOMonitor; @@ -70,26 +71,7 @@ public class AzurePersistence implements SegmentNodeStorePersistence { public AzurePersistence(CloudBlobDirectory segmentStoreDirectory) { this.segmentstoreDirectory = segmentStoreDirectory; - BlobRequestOptions defaultRequestOptions = segmentStoreDirectory.getServiceClient().getDefaultRequestOptions(); - if (defaultRequestOptions.getRetryPolicyFactory() == null) { - int retryAttempts = Integer.getInteger(RETRY_ATTEMPTS_PROP, DEFAULT_RETRY_ATTEMPTS); - if (retryAttempts > 0) { - Integer retryBackoffSeconds = Integer.getInteger(RETRY_BACKOFF_PROP, DEFAULT_RETRY_BACKOFF_SECONDS); - defaultRequestOptions.setRetryPolicyFactory(new RetryLinearRetry((int) TimeUnit.SECONDS.toMillis(retryBackoffSeconds), retryAttempts)); - } - } - if (defaultRequestOptions.getMaximumExecutionTimeInMs() == null) { - int timeoutExecution = Integer.getInteger(TIMEOUT_EXECUTION_PROP, DEFAULT_TIMEOUT_EXECUTION); - if (timeoutExecution > 0) { - defaultRequestOptions.setMaximumExecutionTimeInMs((int) TimeUnit.SECONDS.toMillis(timeoutExecution)); - } - } - if (defaultRequestOptions.getTimeoutIntervalInMs() == null) { - int timeoutInterval = Integer.getInteger(TIMEOUT_INTERVAL_PROP, DEFAULT_TIMEOUT_INTERVAL); - if (timeoutInterval > 0) { - defaultRequestOptions.setTimeoutIntervalInMs((int) TimeUnit.SECONDS.toMillis(timeoutInterval)); - } - } + AzureRequestOptions.applyDefaultRequestOptions(segmentStoreDirectory.getServiceClient().getDefaultRequestOptions()); } @Override diff --git a/oak-segment-azure/src/main/java/org/apache/jackrabbit/oak/segment/azure/AzureSegmentArchiveWriter.java b/oak-segment-azure/src/main/java/org/apache/jackrabbit/oak/segment/azure/AzureSegmentArchiveWriter.java index 3df0eaafa6..e9bbbb322a 100644 --- a/oak-segment-azure/src/main/java/org/apache/jackrabbit/oak/segment/azure/AzureSegmentArchiveWriter.java +++ b/oak-segment-azure/src/main/java/org/apache/jackrabbit/oak/segment/azure/AzureSegmentArchiveWriter.java @@ -25,12 +25,14 @@ import java.io.IOException; import java.net.URISyntaxException; import java.util.concurrent.TimeUnit; +import com.microsoft.azure.storage.blob.BlobRequestOptions; import org.apache.jackrabbit.guava.common.base.Stopwatch; import com.microsoft.azure.storage.StorageException; import com.microsoft.azure.storage.blob.CloudBlobDirectory; import com.microsoft.azure.storage.blob.CloudBlockBlob; import org.apache.jackrabbit.oak.commons.Buffer; +import org.apache.jackrabbit.oak.segment.azure.util.AzureRequestOptions; import org.apache.jackrabbit.oak.segment.remote.WriteAccessController; import org.apache.jackrabbit.oak.segment.azure.util.Retrier; import org.apache.jackrabbit.oak.segment.remote.AbstractRemoteSegmentArchiveWriter; @@ -47,10 +49,13 @@ public class AzureSegmentArchiveWriter extends AbstractRemoteSegmentArchiveWrite Integer.getInteger("azure.segment.archive.writer.retries.intervalMs", 5000) ); + private final BlobRequestOptions writeOptimisedBlobRequestOptions; + public AzureSegmentArchiveWriter(CloudBlobDirectory archiveDirectory, IOMonitor ioMonitor, FileStoreMonitor monitor, WriteAccessController writeAccessController) { super(ioMonitor, monitor); this.archiveDirectory = archiveDirectory; this.writeAccessController = writeAccessController; + this.writeOptimisedBlobRequestOptions = AzureRequestOptions.optimiseForWriteOperations(archiveDirectory.getServiceClient().getDefaultRequestOptions()); } @Override @@ -71,8 +76,8 @@ public class AzureSegmentArchiveWriter extends AbstractRemoteSegmentArchiveWrite Stopwatch stopwatch = Stopwatch.createStarted(); try { blob.setMetadata(AzureBlobMetadata.toSegmentMetadata(indexEntry)); - blob.uploadFromByteArray(data, offset, size); - blob.uploadMetadata(); + blob.uploadFromByteArray(data, offset, size, null, writeOptimisedBlobRequestOptions, null); + blob.uploadMetadata(null, writeOptimisedBlobRequestOptions, null); } catch (StorageException e) { throw new IOException(e); } @@ -97,7 +102,7 @@ public class AzureSegmentArchiveWriter extends AbstractRemoteSegmentArchiveWrite try { writeAccessController.checkWritingAllowed(); - getBlob(getName() + extension).uploadFromByteArray(data, 0, data.length); + getBlob(getName() + extension).uploadFromByteArray(data, 0, data.length, null, writeOptimisedBlobRequestOptions, null); } catch (StorageException e) { throw new IOException(e); } @@ -110,7 +115,7 @@ public class AzureSegmentArchiveWriter extends AbstractRemoteSegmentArchiveWrite try { writeAccessController.checkWritingAllowed(); - getBlob("closed").uploadFromByteArray(new byte[0], 0, 0); + getBlob("closed").uploadFromByteArray(new byte[0], 0, 0, null, writeOptimisedBlobRequestOptions, null); } catch (StorageException e) { throw new IOException(e); } diff --git a/oak-segment-azure/src/main/java/org/apache/jackrabbit/oak/segment/azure/util/AzureRequestOptions.java b/oak-segment-azure/src/main/java/org/apache/jackrabbit/oak/segment/azure/util/AzureRequestOptions.java new file mode 100644 index 0000000000..485612371d --- /dev/null +++ b/oak-segment-azure/src/main/java/org/apache/jackrabbit/oak/segment/azure/util/AzureRequestOptions.java @@ -0,0 +1,63 @@ +package org.apache.jackrabbit.oak.segment.azure.util; + +import com.microsoft.azure.storage.RetryLinearRetry; +import com.microsoft.azure.storage.blob.BlobRequestOptions; + +import java.util.concurrent.TimeUnit; + +public class AzureRequestOptions { + + private static final String RETRY_ATTEMPTS_PROP = "segment.azure.retry.attempts"; + private static final int DEFAULT_RETRY_ATTEMPTS = 5; + + private static final String RETRY_BACKOFF_PROP = "segment.azure.retry.backoff"; + private static final int DEFAULT_RETRY_BACKOFF_SECONDS = 5; + + private static final String TIMEOUT_EXECUTION_PROP = "segment.timeout.execution"; + private static final int DEFAULT_TIMEOUT_EXECUTION = 30; + + private static final String TIMEOUT_INTERVAL_PROP = "segment.timeout.interval"; + private static final int DEFAULT_TIMEOUT_INTERVAL = 1; + + private static final String WRITE_TIMEOUT_EXECUTION_PROP = "segment.write.timeout.execution"; + + private static final String WRITE_TIMEOUT_INTERVAL_PROP = "segment.write.timeout.interval"; + + public static void applyDefaultRequestOptions(BlobRequestOptions blobRequestOptions) { + if (blobRequestOptions.getRetryPolicyFactory() == null) { + int retryAttempts = Integer.getInteger(RETRY_ATTEMPTS_PROP, DEFAULT_RETRY_ATTEMPTS); + if (retryAttempts > 0) { + Integer retryBackoffSeconds = Integer.getInteger(RETRY_BACKOFF_PROP, DEFAULT_RETRY_BACKOFF_SECONDS); + blobRequestOptions.setRetryPolicyFactory(new RetryLinearRetry((int) TimeUnit.SECONDS.toMillis(retryBackoffSeconds), retryAttempts)); + } + } + if (blobRequestOptions.getMaximumExecutionTimeInMs() == null) { + int timeoutExecution = Integer.getInteger(TIMEOUT_EXECUTION_PROP, DEFAULT_TIMEOUT_EXECUTION); + if (timeoutExecution > 0) { + blobRequestOptions.setMaximumExecutionTimeInMs((int) TimeUnit.SECONDS.toMillis(timeoutExecution)); + } + } + if (blobRequestOptions.getTimeoutIntervalInMs() == null) { + int timeoutInterval = Integer.getInteger(TIMEOUT_INTERVAL_PROP, DEFAULT_TIMEOUT_INTERVAL); + if (timeoutInterval > 0) { + blobRequestOptions.setTimeoutIntervalInMs((int) TimeUnit.SECONDS.toMillis(timeoutInterval)); + } + } + } + + public static BlobRequestOptions optimiseForWriteOperations(BlobRequestOptions blobRequestOptions) { + BlobRequestOptions writeOptimisedBlobRequestOptions = new BlobRequestOptions(blobRequestOptions); + + Integer writeTimeoutExecution = Integer.getInteger(WRITE_TIMEOUT_EXECUTION_PROP); + if (writeTimeoutExecution != null) { + writeOptimisedBlobRequestOptions.setMaximumExecutionTimeInMs(writeTimeoutExecution); + } + + Integer writeTimeoutInterval = Integer.getInteger(WRITE_TIMEOUT_INTERVAL_PROP); + if (writeTimeoutInterval != null) { + writeOptimisedBlobRequestOptions.setTimeoutIntervalInMs(writeTimeoutInterval); + } + + return writeOptimisedBlobRequestOptions; + } +}
