This is an automated email from the ASF dual-hosted git repository.

smiklosovic pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/cassandra.git


The following commit(s) were added to refs/heads/trunk by this push:
     new ecaa650a50 Optimize audit logic for batch operations especially when 
audit is not enabled for DML
ecaa650a50 is described below

commit ecaa650a503864bd68f9e570967a8de75f08eb20
Author: Dmitry Konstantinov <[email protected]>
AuthorDate: Fri Sep 5 13:01:20 2025 +0100

    Optimize audit logic for batch operations especially when audit is not 
enabled for DML
    
    Avoid audit batch event creation if audit for batch is not enabled (random 
UIID generation is not very cheap)
    Avoid String.format in a potential hot path
    
    Patch by Dmitry Konstantinov; reviewed by Štefan Miklošovič for 
CASSANDRA-20885
    Co-authored-by: Štefan Miklošovič
---
 CHANGES.txt                                        |  1 +
 .../org/apache/cassandra/audit/AuditLogFilter.java | 11 ++++
 .../apache/cassandra/audit/AuditLogManager.java    | 76 +++++++++++-----------
 3 files changed, 51 insertions(+), 37 deletions(-)

diff --git a/CHANGES.txt b/CHANGES.txt
index f04688c99c..a804fe506b 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
 5.1
+ * Optimize audit logic for batch operations especially when audit is not 
enabled for DML (CASSANDRA-20885)
  * Implement nodetool history (CASSANDRA-20851)
  * Expose StorageService.dropPreparedStatements via JMX (CASSANDRA-20870)
  * Expose Metric for Prepared Statement Cache Size (in bytes) (CASSANDRA-20864)
diff --git a/src/java/org/apache/cassandra/audit/AuditLogFilter.java 
b/src/java/org/apache/cassandra/audit/AuditLogFilter.java
index ec53212bce..1ef2c1b5c1 100644
--- a/src/java/org/apache/cassandra/audit/AuditLogFilter.java
+++ b/src/java/org/apache/cassandra/audit/AuditLogFilter.java
@@ -153,6 +153,17 @@ final class AuditLogFilter
                || isFiltered(auditLogEntry.getUser(), includedUsers, 
excludedUsers);
     }
 
+    boolean isFiltered(AuditLogContext auditLogContext)
+    {
+        return isFiltered(auditLogContext.keyspace, includedKeyspaces, 
excludedKeyspaces)
+               || 
isFiltered(auditLogContext.auditLogEntryType.getCategory().toString(), 
includedCategories, excludedCategories);
+    }
+
+    boolean isFiltered(AuditLogEntryType auditLogEntryType)
+    {
+        return isFiltered(auditLogEntryType.getCategory().toString(), 
includedCategories, excludedCategories);
+    }
+
     /**
      * Checks whether given input is being filtered or not.
      * If excludeSet does not contain any items, by default nothing is 
excluded (unless there are
diff --git a/src/java/org/apache/cassandra/audit/AuditLogManager.java 
b/src/java/org/apache/cassandra/audit/AuditLogManager.java
index 5d82bd9453..f635df4991 100644
--- a/src/java/org/apache/cassandra/audit/AuditLogManager.java
+++ b/src/java/org/apache/cassandra/audit/AuditLogManager.java
@@ -26,7 +26,6 @@ import java.nio.ByteBuffer;
 import java.security.AccessControlContext;
 import java.security.AccessController;
 import java.security.Principal;
-import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
@@ -315,12 +314,47 @@ public class AuditLogManager implements 
QueryEvents.Listener, AuthEvents.Listene
             log(entry, cause, query == null ? null : ImmutableList.of(query));
     }
 
-    public void batchSuccess(BatchStatement.Type batchType, List<? extends 
CQLStatement> statements, List<String> queries, List<List<ByteBuffer>> values, 
QueryOptions options, QueryState state, long queryTime, Message.Response 
response)
+    public void batchSuccess(BatchStatement.Type batchType,
+                             List<? extends CQLStatement> statements,
+                             List<String> queries,
+                             List<List<ByteBuffer>> values,
+                             QueryOptions options,
+                             QueryState state,
+                             long queryStartTimeMillis,
+                             Message.Response response)
     {
-        List<AuditLogEntry> entries = buildEntriesForBatch(statements, 
queries, state, options, queryTime);
-        for (AuditLogEntry auditLogEntry : entries)
+        UUID batchId = null;
+        if (!filter.isFiltered(AuditLogEntryType.BATCH))
         {
-            log(auditLogEntry);
+            batchId = UUID.randomUUID(); // lazy init only if needed, to 
reduce overheads
+            log(new AuditLogEntry.Builder(state)
+                                   .setOperation("BatchId:[" + batchId + "] - 
BATCH of [" + statements.size() + "] statements")
+                                   .setOptions(options)
+                                   .setTimestamp(queryStartTimeMillis)
+                                   .setBatch(batchId)
+                                   .setType(AuditLogEntryType.BATCH)
+                                   .build());
+        }
+
+        for (int i = 0; i < statements.size(); i++)
+        {
+            CQLStatement statement = statements.get(i);
+            if (filter.isFiltered(statement.getAuditLogContext()))
+                continue;
+
+            if (batchId == null)
+                batchId = UUID.randomUUID();
+
+            log(new AuditLogEntry.Builder(state)
+                                  
.setType(statement.getAuditLogContext().auditLogEntryType)
+                                  .setOperation(queries.get(i))
+                                  .setTimestamp(queryStartTimeMillis)
+                                  .setScope(statement)
+                                  .setKeyspace(state, statement)
+                                  .setOptions(options)
+                                  .setBatch(batchId)
+                                  .build());
+
         }
     }
 
@@ -334,38 +368,6 @@ public class AuditLogManager implements 
QueryEvents.Listener, AuthEvents.Listene
         log(entry, cause, queries);
     }
 
-    private static List<AuditLogEntry> buildEntriesForBatch(List<? extends 
CQLStatement> statements, List<String> queries, QueryState state, QueryOptions 
options, long queryStartTimeMillis)
-    {
-        List<AuditLogEntry> auditLogEntries = new 
ArrayList<>(statements.size() + 1);
-        UUID batchId = UUID.randomUUID();
-        String queryString = String.format("BatchId:[%s] - BATCH of [%d] 
statements", batchId, statements.size());
-        AuditLogEntry entry = new AuditLogEntry.Builder(state)
-                              .setOperation(queryString)
-                              .setOptions(options)
-                              .setTimestamp(queryStartTimeMillis)
-                              .setBatch(batchId)
-                              .setType(AuditLogEntryType.BATCH)
-                              .build();
-        auditLogEntries.add(entry);
-
-        for (int i = 0; i < statements.size(); i++)
-        {
-            CQLStatement statement = statements.get(i);
-            entry = new AuditLogEntry.Builder(state)
-                    .setType(statement.getAuditLogContext().auditLogEntryType)
-                    .setOperation(queries.get(i))
-                    .setTimestamp(queryStartTimeMillis)
-                    .setScope(statement)
-                    .setKeyspace(state, statement)
-                    .setOptions(options)
-                    .setBatch(batchId)
-                    .build();
-            auditLogEntries.add(entry);
-        }
-
-        return auditLogEntries;
-    }
-
     public void prepareSuccess(CQLStatement statement, String query, 
QueryState state, long queryTime, ResultMessage.Prepared response)
     {
         AuditLogEntry entry = new 
AuditLogEntry.Builder(state).setOperation(query)


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to