BigTable CheckAndPut的CompareOp.GREATER失效问题技术问询
我来帮你分析这个问题——你遇到的是BigTable HBase客户端1.3.0版本里的一个已知bug,checkAndPut方法在使用CompareOp.GREATER比较操作时,确实存在逻辑错误,导致无论比较结果如何都会执行Put操作。
问题复现细节
你提到的场景完全符合这个bug的表现:现有值("a")字典序小于待比较的值("bbbbbb"),按预期CompareOp.GREATER的checkAndPut应该跳过Put操作,但实际却执行了写入。
使用的依赖
<groupId>com.google.cloud.bigtable</groupId> <artifactId>bigtable-hbase-1.x-hadoop</artifactId> <version>1.3.0</version>
复现代码
byte[] key = "key17".getBytes(); byte[] smaller = "a".getBytes(); byte[] larger = "bbbbbb".getBytes(); byte[] COL_FAMILY = "family".getBytes(); byte[] COL_QUAL = "qual".getBytes(); /** if null, we set it here **/ boolean doRun = table.checkAndPut(key, COL_FAMILY, COL_QUAL, null, new Put(key).addColumn(COL_FAMILY, COL_QUAL, smaller)); System.out.println("WRITE OCCURRED: " + doRun); Result rr = table.get(new Get(key).addFamily(COL_FAMILY)); byte[] res = rr.getValue(COL_FAMILY, COL_QUAL); System.out.println("BEFORE STORED VAL: " + new String(res)); // should NOT put and return false since "a" is NOT greater than "bbbbbb" doRun = table.checkAndPut(key, COL_FAMILY, COL_QUAL, CompareOp.GREATER, larger, new Put(key).addColumn(COL_FAMILY, COL_QUAL, larger)); rr = table.get(new Get(key).addFamily(COL_FAMILY)); res = rr.getValue(COL_FAMILY, COL_QUAL); System.out.println("AFTER STORED VAL: " + new String(res)); System.out.println("WRITE OCCURRED: " + doRun);
实际输出
WRITE OCCURRED: true BEFORE STORED VAL: a AFTER STORED VAL: bbbbbb WRITE OCCURRED: true
问题原因
这个bug源于BigTable HBase客户端早期版本的逻辑反转:在处理CompareOp.GREATER和CompareOp.GREATER_OR_EQUAL这类比较操作时,内部的条件判断被错误地反向处理,导致比较逻辑完全失效,无论现有值和待比较值的关系如何,都会执行Put操作。
解决方案
解决这个问题最直接有效的方式是升级你的BigTable HBase客户端版本。这个bug在后续的1.x系列版本(比如1.5.0及以后的稳定版)中已经被修复,建议升级到最新的1.x系列稳定版本,或者如果你的HBase环境支持,也可以迁移到更现代的2.x系列客户端。
升级后的依赖示例(以1.x系列最新稳定版为例,可根据实际环境调整):
<groupId>com.google.cloud.bigtable</groupId> <artifactId>bigtable-hbase-1.x-hadoop</artifactId> <version>1.23.0</version>
升级后,checkAndPut会正确执行CompareOp.GREATER的逻辑:当现有值小于待比较值时,不会执行Put,返回false;只有当现有值大于待比较值时,才会执行写入并返回true。
验证预期结果
升级后重新运行测试代码,预期输出应该是:
WRITE OCCURRED: true BEFORE STORED VAL: a AFTER STORED VAL: a WRITE OCCURRED: false
这完全符合你最初的预期,第二个checkAndPut不会执行Put操作。
内容的提问来源于stack exchange,提问作者Paul Mazzuca

