Skip to content

HDDS-12835. Recon - Improve NSSummary tasks execution using custom lightweight codec.#8541

Closed
devmadhuu wants to merge 21 commits into
apache:masterfrom
devmadhuu:HDDS-12835
Closed

HDDS-12835. Recon - Improve NSSummary tasks execution using custom lightweight codec.#8541
devmadhuu wants to merge 21 commits into
apache:masterfrom
devmadhuu:HDDS-12835

Conversation

@devmadhuu
Copy link
Copy Markdown
Contributor

What changes were proposed in this pull request?

This PR is to add custom light weight codecs for Recon OM DB to improve the performance of Recon OM tasks including NSSummary tasks execution using custom lightweight codec, as most underlying Recon OM tasks like OMDBInsightTask , NSSummary tasks etc are where it just need very few fields like name, object id, size and parent object Id from KeyInfoTable. Lightweight custom codecs are excluding the de-serialization of ACLs and skipping them altogether as Recon OM tasks doesn't use them.

What is the link to the Apache JIRA

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

How was this patch tested?

This PR is being tested with existing junit and integration tests. Few additional test cases development is in progress.

@devmadhuu devmadhuu changed the title HDDS-12835.Recon - Improve NSSummary tasks execution using custom lightweight codec. HDDS-12835. Recon - Improve NSSummary tasks execution using custom lightweight codec. Jun 2, 2025
@jojochuang jojochuang requested a review from sumitagrawl June 2, 2025 16:18
@devmadhuu devmadhuu marked this pull request as ready for review June 3, 2025 06:49
@adoroszlai
Copy link
Copy Markdown
Contributor

Thanks @devmadhuu for fixing the javadoc. Note there are several test failures due to:

NullPointerException: Cannot invoke "org.apache.ratis.util.function.CheckedFunction.apply(Object)" because "this.backward" is null
	at org.apache.hadoop.hdds.utils.db.DelegatedCodec.toCodecBuffer(DelegatedCodec.java:78)
	at org.apache.hadoop.hdds.utils.db.Codec.toDirectCodecBuffer(Codec.java:66)
	at org.apache.hadoop.hdds.utils.db.TypedTable.put(TypedTable.java:138)
	at org.apache.hadoop.ozone.recon.api.TestOmDBInsightEndPoint.setUpOmData(TestOmDBInsightEndPoint.java:417)
	at org.apache.hadoop.ozone.recon.api.TestOmDBInsightEndPoint.setUp(TestOmDBInsightEndPoint.java:305)

@devmadhuu
Copy link
Copy Markdown
Contributor Author

Thanks @devmadhuu for fixing the javadoc. Note there are several test failures due to:

NullPointerException: Cannot invoke "org.apache.ratis.util.function.CheckedFunction.apply(Object)" because "this.backward" is null
	at org.apache.hadoop.hdds.utils.db.DelegatedCodec.toCodecBuffer(DelegatedCodec.java:78)
	at org.apache.hadoop.hdds.utils.db.Codec.toDirectCodecBuffer(Codec.java:66)
	at org.apache.hadoop.hdds.utils.db.TypedTable.put(TypedTable.java:138)
	at org.apache.hadoop.ozone.recon.api.TestOmDBInsightEndPoint.setUpOmData(TestOmDBInsightEndPoint.java:417)
	at org.apache.hadoop.ozone.recon.api.TestOmDBInsightEndPoint.setUp(TestOmDBInsightEndPoint.java:305)

Yeah @adoroszlai , I am aware of those and looking into it already.

@adoroszlai adoroszlai marked this pull request as draft June 3, 2025 10:13
@devmadhuu devmadhuu marked this pull request as ready for review June 4, 2025 01:26
@devmadhuu devmadhuu requested a review from adoroszlai June 4, 2025 04:53
@adoroszlai adoroszlai removed their request for review June 4, 2025 05:30
import org.apache.hadoop.ozone.protocolPB.OMPBHelper;

/**
* OM database definitions.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Please don't duplicate javadoc from OMDBDefinition. Instead, add a short explanation of how this is different and why it is needed.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done.

Comment on lines +166 to +170
/** volumeTable: /volume :- VolumeInfo. */
public static final DBColumnFamilyDefinition<String, OmVolumeArgs> VOLUME_TABLE_DEF
= new DBColumnFamilyDefinition<>(VOLUME_TABLE,
StringCodec.get(),
OmVolumeArgs.getCodec());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can remove and use from OMDBDefinition?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done.

Comment on lines +257 to +272
* Parses BucketInfo protobuf and creates OmBucketInfo without deserializing ACL list.
* @param bucketInfo
* @return instance of OmBucketInfo
*/
public static OmBucketInfo getOmBucketInfoFromProtobuf(OzoneManagerProtocolProtos.BucketInfo bucketInfo) {
OmBucketInfo.Builder obib = OmBucketInfo.newBuilder()
.setVolumeName(bucketInfo.getVolumeName())
.setBucketName(bucketInfo.getBucketName())
.setIsVersionEnabled(bucketInfo.getIsVersionEnabled())
.setStorageType(StorageType.valueOf(bucketInfo.getStorageType()))
.setCreationTime(bucketInfo.getCreationTime())
.setUsedBytes(bucketInfo.getUsedBytes())
.setModificationTime(bucketInfo.getModificationTime())
.setQuotaInBytes(bucketInfo.getQuotaInBytes())
.setUsedNamespace(bucketInfo.getUsedNamespace())
.setQuotaInNamespace(bucketInfo.getQuotaInNamespace());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Instead of re-implementing most of the conversion logic without ACL, please:

  • move this to OmBucketInfo as a helper that returns OmBucketInfo.Builder
  • let both "full" and "reduced" conversion call the helper and then build(), with "full" adding further logic between the two steps

Apply the same to OmKeyInfo, etc.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@adoroszlai These definition is specific for use case, to keep minimal whatever is required. There can be multiple variation of building the object. eg:

  • may be only need decode parentId and usedSpace
  • may be another need blockList information to be decoded

So I think keeping all in OMBucketInfo is not correct as it can keep changing, and these are to be used within that context, else can have issue.
Code duplicate handing / giving partial method is confusing as it does not define the usecase of the method. So we need keep more close to where its being used, like Recon.

Copy link
Copy Markdown
Contributor

@adoroszlai adoroszlai Jun 11, 2025

Choose a reason for hiding this comment

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

Which makes it trivial to forget about Recon's implementation when changing OMBucketInfo...

Instead of moving to Recon, define the use case in OMBucketInfo instead of just a generic name "...Partial".

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Pls review again. I have tried to refactor by reusing as much as possible.

@devmadhuu devmadhuu requested a review from adoroszlai June 10, 2025 12:04
@adoroszlai adoroszlai dismissed their stale review June 10, 2025 15:56

patch updated

@adoroszlai
Copy link
Copy Markdown
Contributor

Thanks @devmadhuu for updating the patch.

@adoroszlai adoroszlai requested review from ArafatKhan2198 and removed request for adoroszlai June 10, 2025 15:56
= new DBColumnFamilyDefinition<>(DELETED_DIR_TABLE, StringCodec.get(), CUSTOM_CODEC_FOR_KEY_TABLE);

//---------------------------------------------------------------------------
public static final Map<String, DBColumnFamilyDefinition<?, ?>> COLUMN_FAMILIES
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We should avoid creating another map of all, as if any new changes happens, it needs to be updated to Recon Map. The chances of missing is high. Instead, any get operation should get first from this map and then OM's map.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done.

@adoroszlai adoroszlai requested a review from szetszwo June 17, 2025 16:49
Copy link
Copy Markdown
Contributor

@szetszwo szetszwo left a comment

Choose a reason for hiding this comment

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

@devmadhuu , thanks for working on this! Please see the comments inlined.

public static OmBucketInfo getFromProtobuf(BucketInfo bucketInfo,
BucketLayout buckLayout) {
Builder obib = OmBucketInfo.newBuilder()
public static Builder newBuilderFromProtobufPartial(BucketInfo bucketInfo) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

  • Handle all fields in one method follow the same order as in the proto.
  • Add a boolean to include/exclude the large fields.
  • Add javadoc.
  /**
   * Create a builder from the given proto.
   * @param includeLargeFields Omitted the large fields: acl, metadata, beinfo.
   */
  public static Builder newBuilder(BucketInfo bucketInfo, boolean includeLargeFields) {
    final Builder builder = OmBucketInfo.newBuilder()
        .setVolumeName(bucketInfo.getVolumeName())
        .setBucketName(bucketInfo.getBucketName());
    if (includeLargeFields) {
      // acl
      builder.setAcls(bucketInfo.getAclsList().stream().map(
          OzoneAcl::fromProtobuf).collect(Collectors.toList()));
    }
    builder.setIsVersionEnabled(bucketInfo.getIsVersionEnabled())
        .setStorageType(StorageType.valueOf(bucketInfo.getStorageType()))
        .setCreationTime(bucketInfo.getCreationTime());
    if (includeLargeFields) {
      // metadata
      builder.addAllMetadata(KeyValueUtil.getFromProtobuf(bucketInfo.getMetadataList()));

      if (bucketInfo.hasBeinfo()) {
        // beinfo
        builder.setBucketEncryptionKey(OMPBHelper.convert(bucketInfo.getBeinfo()));
      }
    }
    if (bucketInfo.hasObjectID()) {
      builder.setObjectID(bucketInfo.getObjectID());
    }
    if (bucketInfo.hasUpdateID()) {
      builder.setUpdateID(bucketInfo.getUpdateID());
    }
    builder.setModificationTime(bucketInfo.getModificationTime());
    if (bucketInfo.hasSourceVolume()) {
      builder.setSourceVolume(bucketInfo.getSourceVolume());
    }
    if (bucketInfo.hasSourceBucket()) {
      builder.setSourceBucket(bucketInfo.getSourceBucket());
    }
    builder.setUsedBytes(bucketInfo.getUsedBytes())
        .setQuotaInBytes(bucketInfo.getQuotaInBytes())
        .setQuotaInNamespace(bucketInfo.getQuotaInNamespace())
        .setUsedNamespace(bucketInfo.getUsedNamespace())
    if (bucketInfo.hasBucketLayout()) {
      builder.setBucketLayout(BucketLayout.fromProto(bucketInfo.getBucketLayout()));
    }
    if (bucketInfo.hasOwner()) {
      builder.setOwner(bucketInfo.getOwner());
    }
    if (bucketInfo.hasDefaultReplicationConfig()) {
      builder.setDefaultReplicationConfig(
          DefaultReplicationConfig.fromProto(bucketInfo.getDefaultReplicationConfig()));
    }

    return builder;
  }

* @return instance of OmDirectoryInfo
*/
public static OmDirectoryInfo getFromProtobuf(DirectoryInfo dirInfo) {
public static Builder newBuilderFromProtobufPartial(DirectoryInfo dirInfo) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Change it similarly as OmBucketInfo, i.e. use one method to include/exclude large fields.

.setName(dirInfo.getName())
.setCreationTime(dirInfo.getCreationTime())
.setModificationTime(dirInfo.getModificationTime());
if (dirInfo.getMetadataList() != null) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Do we want to include metadata in this case?

Comment on lines +217 to +218
opib.addAllMetadata(KeyValueUtil
.getFromProtobuf(dirInfo.getMetadataList()));
.getFromProtobuf(dirInfo.getMetadataList()));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Combine two lines.

Comment on lines +739 to +740
for (KeyLocationList keyLocationList : keyInfo.getKeyLocationListList()) {
for (OzoneManagerProtocolProtos.KeyLocationList keyLocationList : keyInfo.getKeyLocationListList()) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Revert this change.

Comment on lines +162 to +166
/**
* Parses BucketInfo protobuf and creates OmBucketInfo without deserializing ACL list.
* @param bucketInfo
* @return instance of OmBucketInfo
*/
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This javadoce does not provide any useful information and generate "tag description is missing" warning. Please remove it or rewrite it.

Comment on lines +185 to +189
/**
* Parses DirectoryInfo protobuf and creates OmPrefixInfo.
* @param dirInfo
* @return instance of OmDirectoryInfo
*/
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This javadoce does not provide any useful information and generate "tag description is missing" warning. Please remove it or rewrite it.

private static final Codec<OmBucketInfo> CUSTOM_CODEC_FOR_BUCKET_TABLE = new DelegatedCodec<>(
Proto2Codec.get(OzoneManagerProtocolProtos.BucketInfo.getDefaultInstance()),
ReconOMDBDefinition::getOmBucketInfoFromProtobuf,
null,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Use OmBucketInfo::getProtobuf ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Recon does not write or serialize data to bucket table. Only needed for forward.

public static final DBColumnFamilyDefinition<String, OmBucketInfo> BUCKET_TABLE_DEF
= new DBColumnFamilyDefinition<>(BUCKET_TABLE, StringCodec.get(), CUSTOM_CODEC_FOR_BUCKET_TABLE);

public static final Codec<OmKeyInfo> CUSTOM_CODEC_FOR_KEY_TABLE = new DelegatedCodec<>(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It is not only for KEY_TABLE. Let's rename it to CUSTOM_OM_KEY_INFO_CODEC.

Comment on lines +190 to +191
Table<String, OmDirectoryInfo> dirTable = omMetadataManager.getStore()
.getTable(DIRECTORY_TABLE, StringCodec.get(), CUSTOM_CODEC_FOR_DIR_TABLE, TableCache.CacheType.NO_CACHE);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Use DEF:

      final Table<String, OmDirectoryInfo> dirTable = ReconOMDBDefinition.DIRECTORY_TABLE_DEF
          .getTable(omMetadataManager.getStore());

@devmadhuu devmadhuu requested a review from szetszwo June 27, 2025 13:22
@devmadhuu
Copy link
Copy Markdown
Contributor Author

Test failures in this PR doesn't seem related to the PR change.

Copy link
Copy Markdown
Contributor

@sumitagrawl sumitagrawl left a comment

Choose a reason for hiding this comment

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

IMO, this PR is no longer needed as,

  1. ACL issue is fixed with most probable size is "1" only
  2. metadata size is mostly "0" except for eTag case where normally size is "1"
    So this may not provide much signification improvement in performance.

@devmadhuu
Copy link
Copy Markdown
Contributor Author

IMO, this PR is no longer needed as,

1. ACL issue is fixed with most probable size is "1" only

2. metadata size is mostly "0" except for eTag case where normally size is "1"
   So this may not provide much signification improvement in performance.

Ok, then we can close this PR with this understanding.

@devmadhuu devmadhuu closed this Jul 11, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants