Skip to content

Commit

Permalink
SeekableByteChannel API changes (#34163)
Browse files Browse the repository at this point in the history
* upgrade core dependency

* remove Response<T> from return type

* rename getters/setters for chunk sizes

* expandable string enums

* re-final BlockBlobClient | swap mocks to mockito
  • Loading branch information
jaschrep-msft authored Mar 22, 2023
1 parent 1228af1 commit d194507
Show file tree
Hide file tree
Showing 33 changed files with 988 additions and 926 deletions.
6 changes: 6 additions & 0 deletions sdk/storage/azure-storage-blob/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,12 @@
<version>3.1</version> <!-- {x-version-update;org.objenesis:objenesis;external_dependency} -->
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>4.5.1</version> <!-- {x-version-update;org.mockito:mockito-core;external_dependency} -->
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public final class BlobSeekableByteChannelReadOptions {

private Long initialPosition;
private BlobRequestConditions requestConditions;
private Integer blockSize;
private Integer readSizeInBytes;
private ConsistentReadControl consistentReadControl;

/**
Expand Down Expand Up @@ -57,22 +57,22 @@ public BlobSeekableByteChannelReadOptions setRequestConditions(BlobRequestCondit
}

/**
* @return The size of each data chunk returned from the service. If block size is large, the channel will make
* fewer network calls, but each individual call will send more data and will therefore take longer.
* @return The size of each data read from the service. If read size is large, the channel will make
* fewer network calls, but each individual call will be larger.
* The default value is 4 MB.
*/
public Integer getBlockSize() {
return blockSize;
public Integer getReadSizeInBytes() {
return readSizeInBytes;
}

/**
* @param blockSize The size of each data chunk returned from the service. If block size is large, the channel
* will make fewer network calls, but each individual call will send more data and will therefore take longer.
* @param readSizeInBytes The size of each data read from the service. If read size is large, the channel will make
* fewer network calls, but each individual call will be larger.
* The default value is 4 MB.
* @return The updated options.
*/
public BlobSeekableByteChannelReadOptions setBlockSize(Integer blockSize) {
this.blockSize = blockSize;
public BlobSeekableByteChannelReadOptions setReadSizeInBytes(Integer readSizeInBytes) {
this.readSizeInBytes = readSizeInBytes;
return this;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@
// Licensed under the MIT License.
package com.azure.storage.blob.options;

import com.azure.core.util.ExpandableStringEnum;
import com.azure.core.util.logging.ClientLogger;
import com.azure.storage.blob.models.AccessTier;
import com.azure.storage.blob.models.BlobHttpHeaders;
import com.azure.storage.blob.models.BlobRequestConditions;
import com.fasterxml.jackson.annotation.JsonCreator;

import java.util.Collection;
import java.util.Map;
import java.util.Objects;

Expand All @@ -19,15 +22,35 @@ public final class BlockBlobSeekableByteChannelWriteOptions {
/**
* Mode to open the channel for writing.
*/
public enum WriteMode {
public static final class WriteMode extends ExpandableStringEnum<WriteMode> {
/**
* Replaces the existing block blob, if any, with the newly written contents. Creates a new blob if none exists.
*/
OVERWRITE,
public static final WriteMode OVERWRITE = fromString("Overwrite");

/**
* Creates or finds a AccessTier from its string representation.
*
* @param name a name to look for.
* @return the corresponding AccessTier.
*/
@JsonCreator
public static WriteMode fromString(String name) {
return fromString(name, WriteMode.class);
}

/**
* Gets known WriteMode values.
*
* @return known WriteMode values.
*/
public static Collection<WriteMode> values() {
return values(WriteMode.class);
}
}

private final WriteMode writeMode;
private Long chunkSize;
private Long blockSizeInBytes;
private BlobHttpHeaders headers;
private Map<String, String> metadata;
private Map<String, String> tags;
Expand All @@ -52,16 +75,16 @@ public WriteMode getWriteMode() {
/**
* @return The size of individual writes to the service.
*/
public Long getChunkSize() {
return chunkSize;
public Long getBlockSizeInBytes() {
return blockSizeInBytes;
}

/**
* @param chunkSize The size of individual writes to the service.
* @param blockSizeInBytes The size of individual writes to the service.
* @return The updated instance.
*/
public BlockBlobSeekableByteChannelWriteOptions setChunkSize(Long chunkSize) {
this.chunkSize = chunkSize;
public BlockBlobSeekableByteChannelWriteOptions setBlockSizeInBytes(Long blockSizeInBytes) {
this.blockSizeInBytes = blockSizeInBytes;
return this;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -401,13 +401,13 @@ public BlobInputStream openInputStream(BlobInputStreamOptions options, Context c
* @return A <code>SeekableByteChannel</code> that represents the channel to use for reading from the blob.
* @throws BlobStorageException If a storage service error occurred.
*/
public Response<BlobSeekableByteChannelReadResult> openSeekableByteChannelRead(
public BlobSeekableByteChannelReadResult openSeekableByteChannelRead(
BlobSeekableByteChannelReadOptions options, Context context) {
context = context == null ? Context.NONE : context;
options = options == null ? new BlobSeekableByteChannelReadOptions() : options;
ConsistentReadControl consistentReadControl = options.getConsistentReadControl() == null
? ConsistentReadControl.ETAG : options.getConsistentReadControl();
int chunkSize = options.getBlockSize() == null ? 4 * Constants.MB : options.getBlockSize();
int chunkSize = options.getReadSizeInBytes() == null ? 4 * Constants.MB : options.getReadSizeInBytes();
long initialPosition = options.getInitialPosition() == null ? 0 : options.getInitialPosition();

ByteBuffer initialRange = ByteBuffer.allocate(chunkSize);
Expand Down Expand Up @@ -458,7 +458,7 @@ public Response<BlobSeekableByteChannelReadResult> openSeekableByteChannelRead(
behaviorClient, initialRange, initialPosition, properties.getBlobSize(), requestConditions);

SeekableByteChannel channel = new StorageSeekableByteChannel(chunkSize, behavior, initialPosition);
return new SimpleResponse<>(response, new BlobSeekableByteChannelReadResult(channel, properties));
return new BlobSeekableByteChannelReadResult(channel, properties);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
* Please refer to the <a href=https://docs.microsoft.com/rest/api/storageservices/understanding-block-blobs--append-blobs--and-page-blobs>Azure Docs</a> for more information.
*/
@ServiceClient(builder = SpecializedBlobClientBuilder.class)
public class BlockBlobClient extends BlobClientBase {
public final class BlockBlobClient extends BlobClientBase {
private static final ClientLogger LOGGER = new ClientLogger(BlockBlobClient.class);

private final BlockBlobAsyncClient client;
Expand Down Expand Up @@ -246,8 +246,8 @@ public SeekableByteChannel openSeekableByteChannelWrite(BlockBlobSeekableByteCha
}

return new StorageSeekableByteChannel(
options.getChunkSize() != null
? options.getChunkSize().intValue()
options.getBlockSizeInBytes() != null
? options.getBlockSizeInBytes().intValue()
: BlobAsyncClient.BLOB_DEFAULT_UPLOAD_BLOCK_SIZE,
new StorageSeekableByteChannelBlockBlobWriteBehavior(this, options.getHeaders(), options.getMetadata(),
options.getTags(), options.getTier(), options.getRequestConditions(), internalMode, null),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class BlobSeekableByteChannelTests extends APISpec {

when: "Channel initialized"
def result = bc.openSeekableByteChannelRead(new BlobSeekableByteChannelReadOptions()
.setBlockSize(streamBufferSize), null).getValue()
.setReadSizeInBytes(streamBufferSize), null)
def channel = result.getChannel()

then: "Channel initialized to position zero"
Expand Down Expand Up @@ -73,7 +73,7 @@ class BlobSeekableByteChannelTests extends APISpec {
def "E2E channel write - block"() {
when: "Channel initialized"
def channel = blockClient.openSeekableByteChannelWrite(
new BlockBlobSeekableByteChannelWriteOptions(WriteMode.OVERWRITE).setChunkSize(streamBufferSize))
new BlockBlobSeekableByteChannelWriteOptions(WriteMode.OVERWRITE).setBlockSizeInBytes(streamBufferSize))

then: "Channel initialized to position zero"
channel.position() == 0
Expand Down Expand Up @@ -155,8 +155,8 @@ class BlobSeekableByteChannelTests extends APISpec {
when: "make channel in read mode"
bc.upload(BinaryData.fromBytes(getRandomByteArray(1024)))
def channel = bc.openSeekableByteChannelRead(new BlobSeekableByteChannelReadOptions()
.setRequestConditions(conditions).setBlockSize(blockSize).setConsistentReadControl(control)
.setInitialPosition(position), null).getValue().getChannel() as StorageSeekableByteChannel
.setRequestConditions(conditions).setReadSizeInBytes(blockSize).setConsistentReadControl(control)
.setInitialPosition(position), null).getChannel() as StorageSeekableByteChannel

then: "channel WriteBehavior is null"
channel.getWriteBehavior() == null
Expand Down Expand Up @@ -198,7 +198,7 @@ class BlobSeekableByteChannelTests extends APISpec {
def "Client creates appropriate channel writemode - block"() {
when: "make channel in write mode"
def channel = blockClient.openSeekableByteChannelWrite(
new BlockBlobSeekableByteChannelWriteOptions(writeMode).setChunkSize(blockSize).setHeaders(headers)
new BlockBlobSeekableByteChannelWriteOptions(writeMode).setBlockSizeInBytes(blockSize).setHeaders(headers)
.setMetadata(metadata).setTags(tags).setTier(tier).setRequestConditions(conditions)
) as StorageSeekableByteChannel

Expand All @@ -207,7 +207,7 @@ class BlobSeekableByteChannelTests extends APISpec {

and: "channel WriteBehavior has appropriate values"
def writeBehavior = channel.getWriteBehavior() as StorageSeekableByteChannelBlockBlobWriteBehavior
writeBehavior.getWriteMode() == StorageSeekableByteChannelBlockBlobWriteBehavior.WriteMode.valueOf(writeMode.toString())
writeBehavior.getWriteMode().toString().equalsIgnoreCase(writeMode.toString())
writeBehavior.getHeaders() == headers
writeBehavior.getMetadata() == metadata
writeBehavior.getTags() == tags
Expand Down
Loading

0 comments on commit d194507

Please sign in to comment.