[
https://issues.apache.org/jira/browse/HBASE-29217?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17938931#comment-17938931
]
ruanhui commented on HBASE-29217:
---------------------------------
Thanks for your reply. After revisiting HRegion#checkAndMutateInternal, I think
you are right and I agree with your solution.
Here is my opinion. I think the problem is that when filters are set, an empty
cell can also meet some of the filter requirements, such as EQUAL NULL. But
currently, once the result is empty, we think it's unmatched, so the example I
gave above does not work. I think we can still determine whether the filter
requirements are met when the result is empty like this:
{code:java}
if (filter != null) {
if (!result.isEmpty()) {
matches = true;
cellTs = result.get(0).getTimestamp();
} else {
// here we create a special 'empty' cell and determine whether the filter
requirements are met
Cell emptyCell = new KeyValue(HConstants.EMPTY_BYTE_ARRAY,
HConstants.EMPTY_BYTE_ARRAY,
HConstants.EMPTY_BYTE_ARRAY,
HConstants.EMPTY_BYTE_ARRAY);
matches = !filter.filterRowKey(emptyCell);
}
} {code}
And Here is a passed UT
{code:java}
@Test
public void testFilterOfNonExistsRow() throws Throwable {
byte[] qualifier = Bytes.toBytes("Q");
// Filter 1: Check column absence
Filter existsFilter = new RowFilter(CompareOperator.EQUAL, new
BinaryComparator(HConstants.EMPTY_BYTE_ARRAY));
// Filter 2: Check value condition if Step 1 fails
Filter valueFilter = new ValueFilter(CompareOperator.EQUAL, new
BinaryComparator(Bytes.toBytes("v1")));
// Parent Filter: compose Filter 1 and Filter 2 with Or
FilterList filterList = new FilterList(
FilterList.Operator.MUST_PASS_ONE, Arrays.asList(existsFilter,
valueFilter));
CheckAndMutate checkAndMutate1 = CheckAndMutate.newBuilder(ROWKEY)
.ifMatches(filterList)
.build(new Put(ROWKEY).addColumn(FAMILY, qualifier, Bytes.toBytes("v1")));
try (Table table = createTable()) {
table.checkAndMutate(checkAndMutate1);
assertEquals("v1", Bytes.toString(
table.get(new Get(ROWKEY).addColumn(FAMILY, qualifier)).getValue(FAMILY,
qualifier)));
}
} {code}
This is just a rough idea, not yet polished, not sure if there are any problems
...
Thanks.
> Enhancement for CheckAndMutate
> ------------------------------
>
> Key: HBASE-29217
> URL: https://issues.apache.org/jira/browse/HBASE-29217
> Project: HBase
> Issue Type: Improvement
> Components: Client, regionserver
> Reporter: Xuesen Liang
> Assignee: Xuesen Liang
> Priority: Major
> Labels: pull-request-available
>
> The current implementation of _CheckAndMutate_ operation provides two
> conditional verification modes:
> 1. Column Non-exists:
> {code:java}
> ifMatches(family, qualifier, CompareOperator.EQUAL, null)
> {code}
> Validates that the specified column does not exist.
> 2. Column Value Comparison/Filter
> {code:java}
> ifMatches(family, qualifier, CompareOperator, value)
> {code}
> OR
> {code:java}
> ifMatches(Filter)
> {code}
> Verifies that the column exists and satisfies the defined comparison/filter
> logic.
>
> *Limitation:*
> The existing API lacks support for composite conditional checks of the form:
> _"Column X either does not exist, OR exists and meets comparison condition"._
>
> *Current Workaround & Risks:*
> To implement this logic, developers must:
> {code:java}
> // Step 1: Check column absence
> checkAndMutate.ifMatches(family, qualifier, CompareOperator.EQUAL, null)
> // Step 2: Check value condition if Step 1 fails
> checkAndMutate.ifMatches(family, qualifier, CompareOperator, value)
> {code}
> This approach introduces following critical issues:
> * Non-atomic Execution: The two-phase check creates race conditions.
> * API Complexity: Forces developers to implement client-side synchronization
> logic.
> * Performance: There are two RPC calls.
>
> *Proposed Solution:*
> Introduce a composite conditional operator:
> {code:java}
> ifNotExistsOr(family, qualifier, CompareOperator, value)
> {code}
>
> *Implementation Benefits:*
> * Atomic Guarantee: Executes the "NOT EXISTS OR SATISFIES" logic in a single
> RPC call.
> * API Simplification: Reduces client-side code complexity.
> This enhancement would align HBase's conditional mutation capabilities with
> modern database systems supporting compound atomic predicates, while
> maintaining backward compatibility.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)