Skip to content

Conversation

@gardenia
Copy link

Please describe your PR in detail:

In OzoneManagerStateMachine when certain write requests complete successfully a summary of that request will be written to a new rocksdb "ledger" table named CompletedRequestInfo

The current CompletedRequestInfo schema is minimal:

/**
 * CompletedRequestInfo table entry
 */
message CompletedRequestInfo {

  optional int64 trxLogIndex = 1;
  required Type cmdType = 2; // Type of the command
  optional string volumeName = 3;
  optional string bucketName = 4;
  optional string keyName = 5;
  optional uint64 creationTime = 6;

  optional CreateKeyOperationArgs       createKeyArgs = 7;
  optional RenameKeyOperationArgs       renameKeyArgs = 8;
  optional DeleteKeyOperationArgs       deleteKeyArgs = 9;
  optional CommitKeyOperationArgs       commitKeyArgs = 10;
  optional CreateDirectoryOperationArgs createDirectoryArgs = 11;
  optional CreateFileOperationArgs      createFileArgs = 12;
}

The use of "optional" for the arguments was based on feedback from the community call where @errose28 made the point that the previous sketch of a schema (using a freeform Map<String, String>) did not jibe well with schema management and this optional pattern had been used in other places to get around that.

This change adds the protobufs and entity class to store the completed event info (with the intent that a consumer can use that data to generate event notifications about changes on the filesystem)

What is the link to the Apache JIRA

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

How was this patch tested?

unit tests

@gardenia gardenia changed the title HDDS-14003. EventNotification: Added protobufs and entity class for storing the ledger of completed events HDDS-14003. EventNotification: Added protobufs and entity class Nov 25, 2025
@github-actions
Copy link

This PR has been marked as stale due to 21 days of inactivity. Please comment or remove the stale label to keep it open. Otherwise, it will be automatically closed in 7 days.

@github-actions github-actions bot added the stale label Dec 23, 2025
@ivandika3 ivandika3 removed the stale label Dec 23, 2025
Copy link
Contributor

@swamirishi swamirishi 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 the patch @gardenia I have left some comments inline. Let me know if it makes sense.

private TypedTable<String, SnapshotInfo> snapshotInfoTable;
private TypedTable<String, String> snapshotRenamedTable;
private TypedTable<String, CompactionLogEntry> compactionLogTable;
private TypedTable<String, OmCompletedRequestInfo> completedRequestInfoTable;
Copy link
Contributor

Choose a reason for hiding this comment

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

Make this TypedTable<Long, OmCompletedRequestInfo> rocksdb would do correct comparison for unsigned longs. We don't have to unnecessarily store a longer string

Copy link
Contributor

Choose a reason for hiding this comment

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

In our case we should be good as long as the txn id is going to be positive and ratis is going to ensure that. I believe we don't have to be worried about overflows from ratis side.

Copy link
Author

Choose a reason for hiding this comment

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

@swamirishi - done. thx

/** completedOperationnfoTable: txId :- OmCompletedRequestInfo. */
public static final DBColumnFamilyDefinition<String, OmCompletedRequestInfo> COMPLETED_REQUEST_INFO_TABLE_DEF
= new DBColumnFamilyDefinition<>(COMPLETED_REQUEST_INFO_TABLE,
StringCodec.get(), // txid (left zeropadded)
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
StringCodec.get(), // txid (left zeropadded)
LongCodec.get()

optional double keysProcessedPct = 13;
}

message CreateKeyOperationArgs {
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we not need an event notify for createVolume/createBucket/createSnapshot/deleteSnapshot?

Copy link
Author

Choose a reason for hiding this comment

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

@swamirishi - I have added createVolume/deleteVolume and createBucket/deleteBucket.

I am not sure if createSnapshot/deleteSnapshot is necessary to capture for the event notification feature and it would mean some schema changes to capture this so I would be interested to hear from other reviewers if you think it is suitable to capture snapshot operations for this event ledger. @errose28, @sumitagrawl , @ivandika3

/**
* OperationType enum
*/
public enum OperationType {
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 we need a separate enum on java side. We can just reuse enum from proto

Copy link
Author

Choose a reason for hiding this comment

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

done. thx

* @param exclusiveReplicatedSize - Snapshot exclusive size w/ replication.
*/
@SuppressWarnings("checkstyle:ParameterNumber")
private OmCompletedRequestInfo(long trxLogIndex,
Copy link
Contributor

Choose a reason for hiding this comment

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

use builder as argument

Copy link
Author

Choose a reason for hiding this comment

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

done. thx

@Override
public Map<String, String> toAuditMap() {
Map<String, String> auditMap = new LinkedHashMap<>();
//auditMap.put(OzoneConsts.VOLUME, getVolumeName());
Copy link
Contributor

Choose a reason for hiding this comment

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

Why commented out code?

Copy link
Author

Choose a reason for hiding this comment

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

I had initially made this class Auditable because it was based on another entity class which was "Auditable" but on reflection that probably is not necessary here so I have removed it. Let me know if you disagree.

* Factory for making standard instance.
*/
/*
public static OmCompletedRequestInfo newInstance(long trxLogIndex,
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is this commented?

Copy link
Author

Choose a reason for hiding this comment

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

again it was based on another entity class which had a similar method contract. But it was never used so I have removed it.

@gardenia gardenia force-pushed the HDDS-14003 branch 3 times, most recently from 9c9a6ce to f0eb620 Compare January 14, 2026 17:08
/**
* DB completed request info table name. Referenced in RDBStore.
*/
public static final String COMPLETED_REQUEST_INFO_TABLE = "completedRequestInfoTable";
Copy link
Contributor

@ChenSammi ChenSammi Jan 28, 2026

Choose a reason for hiding this comment

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

@gardenia , thanks for updating the patch.

This is defined in OMDBDefinition already. Let's remove this unused one.

Copy link
Author

Choose a reason for hiding this comment

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

Done. Thx

*/
message CompletedRequestInfo {

optional int64 trxLogIndex = 1;
Copy link
Contributor

Choose a reason for hiding this comment

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

Should trxLogIndex be required? If trxLogIndex is optional, how to detect a unique record, and check whether the record has been processed already or not.

Copy link
Contributor

Choose a reason for hiding this comment

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

All proto fields should be optional and enforced by the code reading it. Proto3 does not support required fields.

Copy link
Contributor

Choose a reason for hiding this comment

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

OmClientProtocol.proto is proto2.

Copy link
Contributor

Choose a reason for hiding this comment

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

The point is not the current proto version. The point is that required is generally bad practice which is why protobuf has stopped supporting it.

Copy link
Author

Choose a reason for hiding this comment

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

I have left it as optional for now but I can see both sides. @ChenSammi is correct that it doesn't make sense to insert a row without it and it might be somewhat self documenting in the protos to see which fields are required. However, there are indeed checks at the code level to enforce that it is provided.

Copy link
Contributor

Choose a reason for hiding this comment

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

I guess I know the difference between proto2 and proto3. If we really have spent time on code review, it will be easy to found that CompletedRequestInfo has both optional and required fields, so does the other new proto definition introduced. So we either straightforwardly comply with proto2 since OmClientProtocol.proto is proto2, or we follow the proto3 behavior, consistently using optional fields with a clear comment that proto3 behavior is used since it's proto2 definition, make sense?

* Per request type entities to hold arguments
* captured for CompletedRequestInfo
*/
message CreateVolumeOperationArgs {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we define a message, like OperationWithoutArgs, and use it for those operations, so we can reduce the empty message defined for each type?

Copy link
Author

Choose a reason for hiding this comment

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

Good point. The intent of that approach was to have placeholder "args" entities for each operation type we capture so that they could be filled out later with any additional fields we want to capture for those operations (e.g. hflush in the case of create file). However, having thought about your feedback it occurs to me that protobuf allows us to add them later as the need arises and therefore there is no value (unless I've misunderstood something) in having placeholder empty ones at this point.

On that basis I have removed the empty argument messages and fields in the "CompletedOperationInfo" message.

cmdType == that.cmdType &&
creationTime == that.creationTime &&
volumeName.equals(that.volumeName) &&
bucketName.equals(that.bucketName) &&
Copy link
Contributor

@ChenSammi ChenSammi Jan 28, 2026

Choose a reason for hiding this comment

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

Could you add a new unit test for null bucketName and keyName case?

Copy link
Author

Choose a reason for hiding this comment

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

Done. Thx

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants