001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.client; 019 020import static org.junit.jupiter.api.Assertions.assertFalse; 021import static org.junit.jupiter.api.Assertions.assertTrue; 022import static org.junit.jupiter.api.Assertions.fail; 023 024import java.io.IOException; 025import org.apache.hadoop.hbase.CompareOperator; 026import org.apache.hadoop.hbase.io.TimeRange; 027import org.apache.hadoop.hbase.util.Bytes; 028import org.apache.hadoop.hbase.util.EnvironmentEdgeManager; 029import org.junit.jupiter.api.TestTemplate; 030 031@SuppressWarnings("deprecation") 032public class FromClientSideTestCheckAndMutate extends FromClientSideTestBase { 033 034 protected FromClientSideTestCheckAndMutate(Class<? extends ConnectionRegistry> registryImpl, 035 int numHedgedReqs) { 036 super(registryImpl, numHedgedReqs); 037 } 038 039 @TestTemplate 040 public void testCheckAndPut() throws IOException { 041 final byte[] anotherrow = Bytes.toBytes("anotherrow"); 042 final byte[] value2 = Bytes.toBytes("abcd"); 043 TEST_UTIL.createTable(tableName, FAMILY); 044 try (Connection conn = getConnection(); Table table = conn.getTable(tableName)) { 045 Put put1 = new Put(ROW); 046 put1.addColumn(FAMILY, QUALIFIER, VALUE); 047 048 // row doesn't exist, so using non-null value should be considered "not match". 049 boolean ok = 050 table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER).ifEquals(VALUE).thenPut(put1); 051 assertFalse(ok); 052 053 // row doesn't exist, so using "ifNotExists" should be considered "match". 054 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER).ifNotExists().thenPut(put1); 055 assertTrue(ok); 056 057 // row now exists, so using "ifNotExists" should be considered "not match". 058 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER).ifNotExists().thenPut(put1); 059 assertFalse(ok); 060 061 Put put2 = new Put(ROW); 062 put2.addColumn(FAMILY, QUALIFIER, value2); 063 064 // row now exists, use the matching value to check 065 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER).ifEquals(VALUE).thenPut(put2); 066 assertTrue(ok); 067 068 Put put3 = new Put(anotherrow); 069 put3.addColumn(FAMILY, QUALIFIER, VALUE); 070 071 // try to do CheckAndPut on different rows 072 try { 073 table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER).ifEquals(value2).thenPut(put3); 074 fail("trying to check and modify different rows should have failed."); 075 } catch (Exception ignored) { 076 } 077 } 078 } 079 080 @TestTemplate 081 public void testCheckAndMutateWithTimeRange() throws IOException { 082 TEST_UTIL.createTable(tableName, FAMILY); 083 try (Connection conn = getConnection(); Table table = conn.getTable(tableName)) { 084 final long ts = EnvironmentEdgeManager.currentTime() / 2; 085 Put put = new Put(ROW); 086 put.addColumn(FAMILY, QUALIFIER, ts, VALUE); 087 088 boolean ok = 089 table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER).ifNotExists().thenPut(put); 090 assertTrue(ok); 091 092 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 093 .timeRange(TimeRange.at(ts + 10000)).ifEquals(VALUE).thenPut(put); 094 assertFalse(ok); 095 096 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 097 .timeRange(TimeRange.from(ts + 10000)).ifEquals(VALUE).thenPut(put); 098 assertFalse(ok); 099 100 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 101 .timeRange(TimeRange.between(ts + 10000, ts + 20000)).ifEquals(VALUE).thenPut(put); 102 assertFalse(ok); 103 104 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER).timeRange(TimeRange.until(ts)) 105 .ifEquals(VALUE).thenPut(put); 106 assertFalse(ok); 107 108 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER).timeRange(TimeRange.at(ts)) 109 .ifEquals(VALUE).thenPut(put); 110 assertTrue(ok); 111 112 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER).timeRange(TimeRange.from(ts)) 113 .ifEquals(VALUE).thenPut(put); 114 assertTrue(ok); 115 116 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 117 .timeRange(TimeRange.between(ts, ts + 20000)).ifEquals(VALUE).thenPut(put); 118 assertTrue(ok); 119 120 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 121 .timeRange(TimeRange.until(ts + 10000)).ifEquals(VALUE).thenPut(put); 122 assertTrue(ok); 123 124 RowMutations rm = new RowMutations(ROW).add((Mutation) put); 125 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 126 .timeRange(TimeRange.at(ts + 10000)).ifEquals(VALUE).thenMutate(rm); 127 assertFalse(ok); 128 129 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER).timeRange(TimeRange.at(ts)) 130 .ifEquals(VALUE).thenMutate(rm); 131 assertTrue(ok); 132 133 Delete delete = new Delete(ROW).addColumn(FAMILY, QUALIFIER); 134 135 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 136 .timeRange(TimeRange.at(ts + 10000)).ifEquals(VALUE).thenDelete(delete); 137 assertFalse(ok); 138 139 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER).timeRange(TimeRange.at(ts)) 140 .ifEquals(VALUE).thenDelete(delete); 141 assertTrue(ok); 142 } 143 } 144 145 @TestTemplate 146 public void testCheckAndPutWithCompareOp() throws IOException { 147 final byte[] value1 = Bytes.toBytes("aaaa"); 148 final byte[] value2 = Bytes.toBytes("bbbb"); 149 final byte[] value3 = Bytes.toBytes("cccc"); 150 final byte[] value4 = Bytes.toBytes("dddd"); 151 TEST_UTIL.createTable(tableName, FAMILY); 152 try (Connection conn = getConnection(); Table table = conn.getTable(tableName)) { 153 Put put2 = new Put(ROW); 154 put2.addColumn(FAMILY, QUALIFIER, value2); 155 156 Put put3 = new Put(ROW); 157 put3.addColumn(FAMILY, QUALIFIER, value3); 158 159 // row doesn't exist, so using "ifNotExists" should be considered "match". 160 boolean ok = 161 table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER).ifNotExists().thenPut(put2); 162 assertTrue(ok); 163 164 // cell = "bbbb", using "aaaa" to compare only LESS/LESS_OR_EQUAL/NOT_EQUAL 165 // turns out "match" 166 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 167 .ifMatches(CompareOperator.GREATER, value1).thenPut(put2); 168 assertFalse(ok); 169 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 170 .ifMatches(CompareOperator.EQUAL, value1).thenPut(put2); 171 assertFalse(ok); 172 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 173 .ifMatches(CompareOperator.GREATER_OR_EQUAL, value1).thenPut(put2); 174 assertFalse(ok); 175 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 176 .ifMatches(CompareOperator.LESS, value1).thenPut(put2); 177 assertTrue(ok); 178 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 179 .ifMatches(CompareOperator.LESS_OR_EQUAL, value1).thenPut(put2); 180 assertTrue(ok); 181 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 182 .ifMatches(CompareOperator.NOT_EQUAL, value1).thenPut(put3); 183 assertTrue(ok); 184 185 // cell = "cccc", using "dddd" to compare only LARGER/LARGER_OR_EQUAL/NOT_EQUAL 186 // turns out "match" 187 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 188 .ifMatches(CompareOperator.LESS, value4).thenPut(put3); 189 assertFalse(ok); 190 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 191 .ifMatches(CompareOperator.LESS_OR_EQUAL, value4).thenPut(put3); 192 assertFalse(ok); 193 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 194 .ifMatches(CompareOperator.EQUAL, value4).thenPut(put3); 195 assertFalse(ok); 196 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 197 .ifMatches(CompareOperator.GREATER, value4).thenPut(put3); 198 assertTrue(ok); 199 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 200 .ifMatches(CompareOperator.GREATER_OR_EQUAL, value4).thenPut(put3); 201 assertTrue(ok); 202 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 203 .ifMatches(CompareOperator.NOT_EQUAL, value4).thenPut(put2); 204 assertTrue(ok); 205 206 // cell = "bbbb", using "bbbb" to compare only GREATER_OR_EQUAL/LESS_OR_EQUAL/EQUAL 207 // turns out "match" 208 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 209 .ifMatches(CompareOperator.GREATER, value2).thenPut(put2); 210 assertFalse(ok); 211 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 212 .ifMatches(CompareOperator.NOT_EQUAL, value2).thenPut(put2); 213 assertFalse(ok); 214 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 215 .ifMatches(CompareOperator.LESS, value2).thenPut(put2); 216 assertFalse(ok); 217 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 218 .ifMatches(CompareOperator.GREATER_OR_EQUAL, value2).thenPut(put2); 219 assertTrue(ok); 220 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 221 .ifMatches(CompareOperator.LESS_OR_EQUAL, value2).thenPut(put2); 222 assertTrue(ok); 223 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 224 .ifMatches(CompareOperator.EQUAL, value2).thenPut(put3); 225 assertTrue(ok); 226 } 227 } 228 229 @TestTemplate 230 public void testCheckAndDelete() throws IOException { 231 final byte[] value1 = Bytes.toBytes("aaaa"); 232 TEST_UTIL.createTable(tableName, FAMILY); 233 try (Connection conn = getConnection(); Table table = conn.getTable(tableName)) { 234 Put put = new Put(ROW); 235 put.addColumn(FAMILY, QUALIFIER, value1); 236 table.put(put); 237 238 Delete delete = new Delete(ROW); 239 delete.addColumns(FAMILY, QUALIFIER); 240 241 boolean ok = 242 table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER).ifEquals(value1).thenDelete(delete); 243 assertTrue(ok); 244 } 245 } 246 247 @TestTemplate 248 public void testCheckAndDeleteWithCompareOp() throws IOException { 249 final byte[] value1 = Bytes.toBytes("aaaa"); 250 final byte[] value2 = Bytes.toBytes("bbbb"); 251 final byte[] value3 = Bytes.toBytes("cccc"); 252 final byte[] value4 = Bytes.toBytes("dddd"); 253 TEST_UTIL.createTable(tableName, FAMILY); 254 try (Connection conn = getConnection(); Table table = conn.getTable(tableName)) { 255 Put put2 = new Put(ROW); 256 put2.addColumn(FAMILY, QUALIFIER, value2); 257 table.put(put2); 258 259 Put put3 = new Put(ROW); 260 put3.addColumn(FAMILY, QUALIFIER, value3); 261 262 Delete delete = new Delete(ROW); 263 delete.addColumns(FAMILY, QUALIFIER); 264 265 // cell = "bbbb", using "aaaa" to compare only LESS/LESS_OR_EQUAL/NOT_EQUAL 266 // turns out "match" 267 boolean ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 268 .ifMatches(CompareOperator.GREATER, value1).thenDelete(delete); 269 assertFalse(ok); 270 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 271 .ifMatches(CompareOperator.EQUAL, value1).thenDelete(delete); 272 assertFalse(ok); 273 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 274 .ifMatches(CompareOperator.GREATER_OR_EQUAL, value1).thenDelete(delete); 275 assertFalse(ok); 276 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 277 .ifMatches(CompareOperator.LESS, value1).thenDelete(delete); 278 assertTrue(ok); 279 table.put(put2); 280 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 281 .ifMatches(CompareOperator.LESS_OR_EQUAL, value1).thenDelete(delete); 282 assertTrue(ok); 283 table.put(put2); 284 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 285 .ifMatches(CompareOperator.NOT_EQUAL, value1).thenDelete(delete); 286 assertTrue(ok); 287 288 // cell = "cccc", using "dddd" to compare only LARGER/LARGER_OR_EQUAL/NOT_EQUAL 289 // turns out "match" 290 table.put(put3); 291 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 292 .ifMatches(CompareOperator.LESS, value4).thenDelete(delete); 293 assertFalse(ok); 294 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 295 .ifMatches(CompareOperator.LESS_OR_EQUAL, value4).thenDelete(delete); 296 assertFalse(ok); 297 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 298 .ifMatches(CompareOperator.EQUAL, value4).thenDelete(delete); 299 assertFalse(ok); 300 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 301 .ifMatches(CompareOperator.GREATER, value4).thenDelete(delete); 302 assertTrue(ok); 303 table.put(put3); 304 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 305 .ifMatches(CompareOperator.GREATER_OR_EQUAL, value4).thenDelete(delete); 306 assertTrue(ok); 307 table.put(put3); 308 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 309 .ifMatches(CompareOperator.NOT_EQUAL, value4).thenDelete(delete); 310 assertTrue(ok); 311 312 // cell = "bbbb", using "bbbb" to compare only GREATER_OR_EQUAL/LESS_OR_EQUAL/EQUAL 313 // turns out "match" 314 table.put(put2); 315 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 316 .ifMatches(CompareOperator.GREATER, value2).thenDelete(delete); 317 assertFalse(ok); 318 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 319 .ifMatches(CompareOperator.NOT_EQUAL, value2).thenDelete(delete); 320 assertFalse(ok); 321 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 322 .ifMatches(CompareOperator.LESS, value2).thenDelete(delete); 323 assertFalse(ok); 324 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 325 .ifMatches(CompareOperator.GREATER_OR_EQUAL, value2).thenDelete(delete); 326 assertTrue(ok); 327 table.put(put2); 328 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 329 .ifMatches(CompareOperator.LESS_OR_EQUAL, value2).thenDelete(delete); 330 assertTrue(ok); 331 table.put(put2); 332 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 333 .ifMatches(CompareOperator.EQUAL, value2).thenDelete(delete); 334 assertTrue(ok); 335 } 336 } 337}