Skip to content

Conversation

@devmadhuu
Copy link
Contributor

@devmadhuu devmadhuu commented Dec 5, 2022

Currently, the /namsepace/summary endpoint carries only count data. Since it is a summary endpoint at the path level, we could make it more useful with other information as well.

Sample volume and bucket summary API responses

For volumes, we can add fields in OzoneVolume:

{
	"path": "/s3v",
	"type": "VOLUME",
	"counts": {
		"volumes": 0,
		"buckets": 1,
		"directories": 3,
		"object-store-prefixes": 0,
		"keys": 2
	},
	"dbinfo": {
		"metadata": {},
		"name": "s3v",
		"admin": "hadoop",
		"owner": "hadoop",
		"quotaInBytes": -1,
		"quotaInNamespace": -1,
		"usedNamespace": 1,
		"creationTime": "2021-07-27T18:21:40.251Z",
		"modificationTime": "2021-07-27T18:21:40.251Z",
		"acls": []
	},
	"status": "OK"
}

For buckets, we can add fields in OzoneBucket:

{
	"path": "/s3v/s3bucket",
	"type": "BUCKET",
	"counts": {
		"volumes": 0,
		"buckets": 0,
		"directories": 3,
		"object-store-prefixes": 0,
		"keys": 20
	},
	"dbinfo": {
		"metadata": {
			"ozone.om.metadata.layout": "PREFIX",
			"ozone.om.enable.filesystem.paths": "true"
		},
		"volumeName": "s3v",
		"name": "s3bucket",
		"storageType": "DISK",
		"versioning": false,
		"usedBytes": 536870912,
		"usedNamespace": 2,
		"creationTime": "2021-07-27T19:33:54.574Z",
		"modificationTime": "2021-07-27T19:33:54.574Z",
		"encryptionKeyName": null,
		"sourceVolume": null,
		"sourceBucket": null,
		"quotaInBytes": -1,
		"quotaInNamespace": -1
	},
	"status": "OK"
}

Some refactoring of existing code also been done to improve the structuring of API response. All counts related information has been grouped under "CountStats" and "dbInfo" information is added extra for detailed object information picked up from RocksDB for the path for which name space summary is generated.

https://issues.apache.org/jira/browse/HDDS-5541

Patch is tested with writing and executing Junit test cases inside "TestNSSummaryEndpointWithLegacy" and "TestNSSummaryEndpointWithFSO"

@devmadhuu
Copy link
Contributor Author

@smengcl @dombizita , pls review

@kerneltime kerneltime requested a review from smengcl December 5, 2022 17:28
@kerneltime
Copy link
Contributor

@swamirishi @aswinshakil can you please take a look?

Assert.assertSame(entity.getEntityType(), EntityType.DIRECTORY);
Assert.assertEquals(1, entity.getNumTotalKey());
Assert.assertEquals(0, entity.getNumTotalDir());
Assert.assertEquals(1, entity.getCountStats().getNumTotalKey());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why aren't we asserting getNumVolume() and getNumBucket() here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @hemantk-12 for review. Changes done. Pls re-review. This was existing case, I added those missing as you mentioned.

CountStats countStats = new CountStats(
-1, -1,
getTotalDirCount(bucketObjectId), getTotalKeyCount(bucketObjectId));
NamespaceSummaryResponse namespaceSummaryResponse =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
NamespaceSummaryResponse namespaceSummaryResponse =
return NamespaceSummaryResponse.newBuilder()
.setEntityType(EntityType.BUCKET)
.setCountStats(countStats)
.setObjectDBInfo(getBucketObjDbInfo(names))
.setStatus(ResponseStatus.OK)
.build();

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @hemantk-12 for review. Changes done. Pls re-review.

getBucketKey(volName, bucketName);
OmBucketInfo omBucketInfo =
getOmMetadataManager().getBucketTable().getSkipCache(bucketKey);
BucketObjectDBInfo bucketObjectDBInfo = new BucketObjectDBInfo();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Create a constructor or a builder which takes OmBucketInfo in BucketObjectDBInfo. Something like this. This way encapsulation will be preserved.

  public BucketObjectDBInfo(OmBucketInfo omBucketInfo) {
    this.metadata = omBucketInfo.getMetadata();
    this.volumeName = omBucketInfo.getVolumeName();
    this.name = omBucketInfo.getBucketName();
    this.quotaInBytes = omBucketInfo.getQuotaInBytes();
    this.quotaInNamespace = omBucketInfo.getQuotaInNamespace();
    this.usedNamespace = omBucketInfo.getUsedNamespace();
    this.creationTime = omBucketInfo.getCreationTime();
    this.modificationTime = omBucketInfo.getModificationTime();
    this.acls = omBucketInfo.getAcls();
    this.sourceBucket = omBucketInfo.getSourceBucket();
    this.sourceVolume = omBucketInfo.getSourceVolume();
    this.encryptionKeyInfo = omBucketInfo.getEncryptionKeyInfo();
    this.versioningEnabled = omBucketInfo.getIsVersionEnabled();
    this.storageType = omBucketInfo.getStorageType();
    this.defaultReplicationConfig = omBucketInfo.getDefaultReplicationConfig();
    this.bucketLayout = omBucketInfo.getBucketLayout();
    this.owner = omBucketInfo.getOwner();
  }

Builder would be preferred tho.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @hemantk-12 for review. Changes done. Pls re-review.

private ObjectDBInfo getDirectoryObjDbInfo(String[] names)
throws IOException {
OmDirectoryInfo dirInfo = getBucketHandler().getDirInfo(names);
ObjectDBInfo objectDBInfo = new ObjectDBInfo();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as BucketObjectDBInfo, create constructor or builder which takes OmDirectoryInfo and create ObjectDBInfo object.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @hemantk-12 for review. Changes done. Pls re-review.

private ObjectDBInfo getKeyDbObjectInfo(String[] names)
throws IOException {
OmKeyInfo keyInfo = getBucketHandler().getKeyInfo(names);
KeyObjectDBInfo keyObjectDBInfo = new KeyObjectDBInfo();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as BucketObjectDBInfo, create constructor or builder which takes OmKeyInfo and create KeyObjectDBInfo object.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @hemantk-12 for review. Changes done. Pls re-review.

OmPrefixInfo omPrefixInfo =
getOmMetadataManager().getPrefixTable().
getSkipCache(OzoneConsts.OM_KEY_PREFIX);
ObjectDBInfo objectDBInfo = new ObjectDBInfo();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as BucketObjectDBInfo, create constructor or builder which takes OmPrefixInfo and create ObjectDBInfo object.

String dbVolumeKey = getOmMetadataManager().getVolumeKey(names[0]);
OmVolumeArgs volumeArgs =
getOmMetadataManager().getVolumeTable().getSkipCache(dbVolumeKey);
VolumeObjectDBInfo objectDBInfo = new VolumeObjectDBInfo();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as BucketObjectDBInfo, create constructor or builder which takes OmVolumeArgs and create VolumeObjectDBInfo object.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @hemantk-12 for review. Changes done. Pls re-review.

Comment on lines 416 to 419
Assert.assertEquals(2, rootResponseObj.getCountStats().getNumVolume());
Assert.assertEquals(4, rootResponseObj.getCountStats().getNumBucket());
Assert.assertEquals(5, rootResponseObj.getCountStats().getNumTotalDir());
Assert.assertEquals(10, rootResponseObj.getCountStats().getNumTotalKey());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a repetitive code. I think moving this to a function would be nicer.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @hemantk-12 for review. Changes done. Pls re-review.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is addressed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My bad, it has been fixed.

@JsonProperty("replicationConfigInfo")
private DefaultReplicationConfig defaultReplicationConfig;

/** source volume. */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Java doc comments, like this, don't provide any information as such. I would recommend to remove obvious comments like this everywhere.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @hemantk-12 for review. Changes done. Pls re-review.

if (!isInitializationComplete()) {
namespaceSummaryResponse =
new NamespaceSummaryResponse(EntityType.UNKNOWN);
NamespaceSummaryResponse.newBuilder().
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
NamespaceSummaryResponse.newBuilder().
NamespaceSummaryResponse.newBuilder()
.setEntityType(EntityType.UNKNOWN)
.setStatus(ResponseStatus.INITIALIZING)
.build();

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hemantk-12 - this is fixed. pls re-review.

Comment on lines 63 to 69
return
NamespaceSummaryResponse.newBuilder()
.setEntityType(EntityType.BUCKET)
.setCountStats(countStats)
.setObjectDBInfo(getBucketObjDbInfo(names))
.setStatus(ResponseStatus.OK)
.build();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It could be in one line. Please change it everywhere.

Suggested change
return
NamespaceSummaryResponse.newBuilder()
.setEntityType(EntityType.BUCKET)
.setCountStats(countStats)
.setObjectDBInfo(getBucketObjDbInfo(names))
.setStatus(ResponseStatus.OK)
.build();
return NamespaceSummaryResponse.newBuilder()
.setEntityType(EntityType.VOLUME)
.setCountStats(countStats)
.setObjectDBInfo(getVolumeObjDbInfo(names))
.setStatus(ResponseStatus.OK)
.build();

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hemantk-12 - this is fixed. pls re-review.


}

public BucketObjectDBInfo(Builder b) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not how builder pattern works. Please change all the builder to this way.

Suggested change
public BucketObjectDBInfo(Builder b) {
public BucketObjectDBInfo(Map<String, String> metadata,
String name,
String volumeName,
StorageType storageType,
boolean isVersioningEnabled,
BucketEncryptionKeyInfo bekInfo,
DefaultReplicationConfig defaultReplicationConfig,
String sourceVolume,
String sourceBucket,
BucketLayout bucketLayout,
String owner,
long quotaInBytes,
long quotaInNamespace,
long usedNamespace,
long creationTime,
long modificationTime,
List<OzoneAcl> acls) {
super.setMetadata(metadata);
super.setName(name);
super.setQuotaInBytes(quotaInBytes);
super.setQuotaInNamespace(quotaInNamespace);
super.setUsedNamespace(usedNamespace);
super.setCreationTime(creationTime);
super.setModificationTime(modificationTime);
super.setAcls(acls);
this.volumeName = volumeName;
this.sourceBucket = sourceVolume;
this.sourceVolume = sourceBucket;
this.isVersioningEnabled = isVersioningEnabled;
this.storageType = storageType;
this.defaultReplicationConfig = defaultReplicationConfig;
this.bucketLayout = bucketLayout;
this.owner = owner;
this.bekInfo = bekInfo;
}

More: https://www.baeldung.com/java-builder-pattern-freebuilder

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hemantk-12 - there can be multiple ways to implement builder pattern. We should just make sure that OOPS principles being followed. You may want to look below link as well.

https://www.geeksforgeeks.org/builder-pattern-in-java/

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hemantk-12 - As discussed, implemented with plain constructor Pls re-review.

* Builder for BucketObjectDBInfo.
*/
@SuppressWarnings("checkstyle:hiddenfield")
public static final class Builder {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
public static final class Builder {
public static class Builder {
private final OmBucketInfo omBucketInfo;
public Builder(OmBucketInfo omBucketInfo) {
this.omBucketInfo = omBucketInfo;
}
public BucketObjectDBInfo build() {
if (this.omBucketInfo == null) {
return new BucketObjectDBInfo();
}
return new BucketObjectDBInfo(omBucketInfo.getMetadata(),
omBucketInfo.getBucketName(),
omBucketInfo.getVolumeName(),
omBucketInfo.getStorageType(),
omBucketInfo.getIsVersionEnabled(),
omBucketInfo.getEncryptionKeyInfo(),
omBucketInfo.getDefaultReplicationConfig(),
omBucketInfo.getSourceVolume(),
omBucketInfo.getSourceBucket(),
omBucketInfo.getBucketLayout(),
omBucketInfo.getOwner(),
omBucketInfo.getQuotaInBytes(),
omBucketInfo.getQuotaInNamespace(),
omBucketInfo.getUsedNamespace(),
omBucketInfo.getCreationTime(),
omBucketInfo.getModificationTime(),
omBucketInfo.getAcls());
}
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hemantk-12 - This is just a specific pattern you mentioned. Builder pattern can be written in many ways. We can discuss over this in Slack channel. I have pinged you. You can let me know when you are free to discuss.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hemantk-12 - As discussed, implemented with plain constructor Pls re-review.

return volumeName;
}

public void setVolumeName(String volumeName) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need setter? Is it for jackson serialization?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hemantk-12 - yes it is needed for JSON serialization

/**
* Encapsulates the low level volume/bucket/dir info.
*/
public class ObjectDBInfo {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we just call it ObjectInfo? Why DB in the name?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hemantk-12 - It is because these attributes are very specific to what we save in RocksDB. Pls also you can go through JIRA details.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hemantk-12 - As discussed, we have kept the name same as ObjectDBInfo. Pls re-review.

/**
* Encapsulates the low level bucket info.
*/
public class BucketObjectDBInfo extends ObjectDBInfo {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it really a subclass of ObjectDBInfo? Or you just did it because they share some common properties?

It also doesn't follow the correct hierarchy model.
Java doc comment says VolumeObjectDBInfo encapsulates the low level volume info, BucketObjectDBInfo encapsulates the low level bucket info and ObjectDBInfoEncapsulates the low level volume/bucket/dir info.

So hierarchy should be Volume -> Bucket -> Dir -> Key but according to your implementation Dir -> Volume, Bucket and Key. Which is wrong to me.

Please correct it. If you want to extract out common properties, create another class something CommonPropertyClass (Please come up with better name).

VolumeObjectDBInfo extands CommonPropertyClass
BucketObjectDBInfo extands CommonPropertyClass
ObjectDBInfo extands CommonPropertyClass
KeyObjectDBInfo extands CommonPropertyClass

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hemantk-12 , thanks for your review. Here we don't have to follow that Volume -> Bucket -> Dir -> Key
Because this ObjectDBInfo is a parent class with common properties.
Because this is RocksDB object level info properties and I feel giving name as ObjectDBInfo is justifying name... as this is no specific objectDB info and attributes can be related to any object which is common... So either we can give name as CommonPropertyClass or ObjectDBInfo, how does it matter. It is just an implementation specific I believe.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it really a subclass of ObjectDBInfo? Or you just did it because they share some common properties?

It also doesn't follow the correct hierarchy model. Java doc comment says VolumeObjectDBInfo encapsulates the low level volume info, BucketObjectDBInfo encapsulates the low level bucket info and ObjectDBInfoEncapsulates the low level volume/bucket/dir info.

So hierarchy should be Volume -> Bucket -> Dir -> Key but according to your implementation Dir -> Volume, Bucket and Key. Which is wrong to me.

Please correct it. If you want to extract out common properties, create another class something CommonPropertyClass (Please come up with better name).

VolumeObjectDBInfo extands CommonPropertyClass
BucketObjectDBInfo extands CommonPropertyClass
ObjectDBInfo extands CommonPropertyClass
KeyObjectDBInfo extands CommonPropertyClass

@hemantk-12 - As discussed, we have kept the name same as ObjectDBInfo. Pls re-review.

@JsonProperty("owner")
private String owner;

public static BucketObjectDBInfo.Builder newBuilder() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is unnecessary function.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hemantk-12 - I couldn't understand this. Pls elaborate why unnecessary.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because new BucketObjectDBInfo.Builder(); can be used instead of BucketObjectDBInfo.newBuilder() . It is not providing any benefit.

If it is general pattern followed in the code base, please go ahead with it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hemantk-12 - As discussed, I have implemented without builder and with plain constructor. Pls re-review.

Comment on lines 416 to 419
Assert.assertEquals(2, rootResponseObj.getCountStats().getNumVolume());
Assert.assertEquals(4, rootResponseObj.getCountStats().getNumBucket());
Assert.assertEquals(5, rootResponseObj.getCountStats().getNumTotalDir());
Assert.assertEquals(10, rootResponseObj.getCountStats().getNumTotalKey());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is addressed.

Copy link
Contributor

@hemantk-12 hemantk-12 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

@Override
public OmDirectoryInfo getDirInfo(String[] names) throws IOException {
return OmDirectoryInfo.newBuilder()
.setName(names[2])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If names has less than 3 elements, iirc it throws ArrayIndexOutOfBoundsException which is a RuntimeException and won't be caught by IOException.

Add a Preconditions.checkArgument check here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@smengcl - this check is not needed here as above code flow hits only when the path will be directory else not.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you explain more, what guarantees that we can't call this getDirInfo method only when the path is a directory? this is inside BucketHandler and a legacy bucket doesn't necessarily have a directory inside.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@devmadhuu I get that the only caller (at the moment) calling this method won't cause issues. I'm fine with either adding or not adding the check but I would prefer the former.

Same goes for the method in FSOBucketHandler.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dombizita - getDirInfo method has caller only through DirectoryEntityHandler and call stack for DirectoryEntityHandler will be determined after validating the path , if path is directory, then only DirectoryEntityHandler will be returned by EntityHandler.getEntityHandler , so there is no way the current code flow will hit getDirInfo method if path is not directory. First two indexes will be taken by Volume and Bucket in path and 3rd index will be surely a directory. Please check the caller hierarchy of this method. We can have zoom call to explain by sharing my screen.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get that currently this is only called when it is guaranteed that the path is a directory. but if someone later adds something and doesn't know how this method works the scenario can happen which @smengcl wrote above. all the classes that are extending the EntityHandler abstract class can do a OmDirectoryInfo omDirectoryInfo = getBucketHandler().getDirInfo(names), even if the names length is less than 3. I am also fine with either way, just wanted to clarify what I meant.

Copy link
Contributor

@smengcl smengcl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @devmadhuu for working on this. Overall looks fine.

Copy link
Contributor

@dombizita dombizita left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for this useful improvement @devmadhuu, I added few comment inline, beside that it looks good to me.

@Override
public OmDirectoryInfo getDirInfo(String[] names) throws IOException {
return OmDirectoryInfo.newBuilder()
.setName(names[2])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you explain more, what guarantees that we can't call this getDirInfo method only when the path is a directory? this is inside BucketHandler and a legacy bucket doesn't necessarily have a directory inside.

* Encapsulates the low level bucket info.
*/
public class BucketObjectDBInfo extends ObjectDBInfo {
@JsonProperty("volumeName")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is the difference between volumeName and sourceVolume (in line 52)?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sourceVolume is used for bucket link iirc.

Pair.of(info.getSourceVolume(), info.getSourceBucket()),

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is the difference between volumeName and sourceVolume (in line 52)?

@dombizita - SourceVolume is used if bucket is a symbolic link.

@dombizita
Copy link
Contributor

thanks for updating your patch @devmadhuu, it looks good to me!

@siddhantsangwan
Copy link
Contributor

siddhantsangwan commented Jan 11, 2023

@devmadhuu Thanks for the contribution. Thanks everyone for reviewing. Merging this now that we have approvals.

@siddhantsangwan siddhantsangwan merged commit de53086 into apache:master Jan 11, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants