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 org.apache.hadoop.hbase.CompareOperator; 021import org.apache.hadoop.hbase.filter.Filter; 022import org.apache.hadoop.hbase.io.TimeRange; 023import org.apache.hadoop.hbase.util.Bytes; 024import org.apache.yetus.audience.InterfaceAudience; 025import org.apache.yetus.audience.InterfaceStability; 026 027import org.apache.hbase.thirdparty.com.google.common.base.Preconditions; 028 029/** 030 * Used to perform CheckAndMutate operations. 031 * <p> 032 * Use the builder class to instantiate a CheckAndMutate object. This builder class is fluent style 033 * APIs, the code are like: 034 * 035 * <pre> 036 * <code> 037 * // A CheckAndMutate operation where do the specified action if the column (specified by the 038 * // family and the qualifier) of the row equals to the specified value 039 * CheckAndMutate checkAndMutate = CheckAndMutate.newBuilder(row) 040 * .ifEquals(family, qualifier, value) 041 * .build(put); 042 * 043 * // A CheckAndMutate operation where do the specified action if the column (specified by the 044 * // family and the qualifier) of the row doesn't exist 045 * CheckAndMutate checkAndMutate = CheckAndMutate.newBuilder(row) 046 * .ifNotExists(family, qualifier) 047 * .build(put); 048 * 049 * // A CheckAndMutate operation where do the specified action if the row matches the filter 050 * CheckAndMutate checkAndMutate = CheckAndMutate.newBuilder(row) 051 * .ifMatches(filter) 052 * .build(delete); 053 * </code> 054 * </pre> 055 */ 056@InterfaceAudience.Public 057@InterfaceStability.Evolving 058public final class CheckAndMutate implements Row { 059 060 /** 061 * A builder class for building a CheckAndMutate object. 062 */ 063 @InterfaceAudience.Public 064 @InterfaceStability.Evolving 065 public static final class Builder { 066 private final byte[] row; 067 private byte[] family; 068 private byte[] qualifier; 069 private CompareOperator op; 070 private byte[] value; 071 private Filter filter; 072 private TimeRange timeRange; 073 private boolean queryMetricsEnabled = false; 074 075 private Builder(byte[] row) { 076 this.row = Preconditions.checkNotNull(row, "row is null"); 077 } 078 079 /** 080 * Check for lack of column 081 * @param family family to check 082 * @param qualifier qualifier to check 083 * @return the CheckAndMutate object 084 */ 085 public Builder ifNotExists(byte[] family, byte[] qualifier) { 086 return ifEquals(family, qualifier, null); 087 } 088 089 /** 090 * Check for equality 091 * @param family family to check 092 * @param qualifier qualifier to check 093 * @param value the expected value 094 * @return the CheckAndMutate object 095 */ 096 public Builder ifEquals(byte[] family, byte[] qualifier, byte[] value) { 097 return ifMatches(family, qualifier, CompareOperator.EQUAL, value); 098 } 099 100 /** 101 * Check for match 102 * @param family family to check 103 * @param qualifier qualifier to check 104 * @param compareOp comparison operator to use 105 * @param value the expected value 106 * @return the CheckAndMutate object 107 */ 108 public Builder ifMatches(byte[] family, byte[] qualifier, CompareOperator compareOp, 109 byte[] value) { 110 this.family = Preconditions.checkNotNull(family, "family is null"); 111 this.qualifier = qualifier; 112 this.op = Preconditions.checkNotNull(compareOp, "compareOp is null"); 113 this.value = value; 114 return this; 115 } 116 117 /** 118 * Check for match 119 * @param filter filter to check 120 * @return the CheckAndMutate object 121 */ 122 public Builder ifMatches(Filter filter) { 123 this.filter = Preconditions.checkNotNull(filter, "filter is null"); 124 return this; 125 } 126 127 /** 128 * Specify a timerange 129 * @param timeRange time range to check 130 * @return the CheckAndMutate object 131 */ 132 public Builder timeRange(TimeRange timeRange) { 133 this.timeRange = timeRange; 134 return this; 135 } 136 137 /** 138 * Enables the return of {@link QueryMetrics} alongside the corresponding result for this query 139 * <p> 140 * This is intended for advanced users who need result-granular, server-side metrics 141 * <p> 142 * Does not work 143 * @param queryMetricsEnabled {@code true} to enable collection of per-result query metrics 144 * {@code false} to disable metrics collection (resulting in 145 * {@code null} metrics) 146 */ 147 public Builder queryMetricsEnabled(boolean queryMetricsEnabled) { 148 this.queryMetricsEnabled = queryMetricsEnabled; 149 return this; 150 } 151 152 private void preCheck(Row action) { 153 Preconditions.checkNotNull(action, "action is null"); 154 if (!Bytes.equals(row, action.getRow())) { 155 throw new IllegalArgumentException( 156 "The row of the action <" + Bytes.toStringBinary(action.getRow()) 157 + "> doesn't match the original one <" + Bytes.toStringBinary(this.row) + ">"); 158 } 159 Preconditions.checkState(op != null || filter != null, 160 "condition is null. You need to" 161 + " specify the condition by calling ifNotExists/ifEquals/ifMatches before building a" 162 + " CheckAndMutate object"); 163 } 164 165 /** 166 * Build the CheckAndMutate object 167 * @param put data to put if check succeeds 168 * @return a CheckAndMutate object 169 */ 170 public CheckAndMutate build(Put put) { 171 preCheck(put); 172 if (filter != null) { 173 return new CheckAndMutate(row, filter, timeRange, put, queryMetricsEnabled); 174 } else { 175 return new CheckAndMutate(row, family, qualifier, op, value, timeRange, put, 176 queryMetricsEnabled); 177 } 178 } 179 180 /** 181 * Build the CheckAndMutate object 182 * @param delete data to delete if check succeeds 183 * @return a CheckAndMutate object 184 */ 185 public CheckAndMutate build(Delete delete) { 186 preCheck(delete); 187 if (filter != null) { 188 return new CheckAndMutate(row, filter, timeRange, delete, queryMetricsEnabled); 189 } else { 190 return new CheckAndMutate(row, family, qualifier, op, value, timeRange, delete, 191 queryMetricsEnabled); 192 } 193 } 194 195 /** 196 * Build the CheckAndMutate object with an Increment to commit if the check succeeds. 197 * @param increment data to increment if check succeeds 198 * @return a CheckAndMutate object 199 */ 200 public CheckAndMutate build(Increment increment) { 201 preCheck(increment); 202 if (filter != null) { 203 return new CheckAndMutate(row, filter, timeRange, increment, queryMetricsEnabled); 204 } else { 205 return new CheckAndMutate(row, family, qualifier, op, value, timeRange, increment, 206 queryMetricsEnabled); 207 } 208 } 209 210 /** 211 * Build the CheckAndMutate object with an Append to commit if the check succeeds. 212 * @param append data to append if check succeeds 213 * @return a CheckAndMutate object 214 */ 215 public CheckAndMutate build(Append append) { 216 preCheck(append); 217 if (filter != null) { 218 return new CheckAndMutate(row, filter, timeRange, append, queryMetricsEnabled); 219 } else { 220 return new CheckAndMutate(row, family, qualifier, op, value, timeRange, append, 221 queryMetricsEnabled); 222 } 223 } 224 225 /** 226 * Build the CheckAndMutate object with a RowMutations to commit if the check succeeds. 227 * @param mutations mutations to perform if check succeeds 228 * @return a CheckAndMutate object 229 */ 230 public CheckAndMutate build(RowMutations mutations) { 231 preCheck(mutations); 232 if (filter != null) { 233 return new CheckAndMutate(row, filter, timeRange, mutations, queryMetricsEnabled); 234 } else { 235 return new CheckAndMutate(row, family, qualifier, op, value, timeRange, mutations, 236 queryMetricsEnabled); 237 } 238 } 239 } 240 241 /** 242 * returns a builder object to build a CheckAndMutate object 243 * @param row row 244 * @return a builder object 245 */ 246 public static Builder newBuilder(byte[] row) { 247 return new Builder(row); 248 } 249 250 private final byte[] row; 251 private final byte[] family; 252 private final byte[] qualifier; 253 private final CompareOperator op; 254 private final byte[] value; 255 private final Filter filter; 256 private final TimeRange timeRange; 257 private final Row action; 258 private final boolean queryMetricsEnabled; 259 260 private CheckAndMutate(byte[] row, byte[] family, byte[] qualifier, final CompareOperator op, 261 byte[] value, TimeRange timeRange, Row action, boolean queryMetricsEnabled) { 262 this.row = row; 263 this.family = family; 264 this.qualifier = qualifier; 265 this.op = op; 266 this.value = value; 267 this.filter = null; 268 this.timeRange = timeRange != null ? timeRange : TimeRange.allTime(); 269 this.action = action; 270 this.queryMetricsEnabled = queryMetricsEnabled; 271 } 272 273 private CheckAndMutate(byte[] row, Filter filter, TimeRange timeRange, Row action, 274 boolean queryMetricsEnabled) { 275 this.row = row; 276 this.family = null; 277 this.qualifier = null; 278 this.op = null; 279 this.value = null; 280 this.filter = filter; 281 this.timeRange = timeRange != null ? timeRange : TimeRange.allTime(); 282 this.action = action; 283 this.queryMetricsEnabled = queryMetricsEnabled; 284 } 285 286 /** Returns the row */ 287 @Override 288 public byte[] getRow() { 289 return row; 290 } 291 292 /** Returns the family to check */ 293 public byte[] getFamily() { 294 return family; 295 } 296 297 /** Returns the qualifier to check */ 298 public byte[] getQualifier() { 299 return qualifier; 300 } 301 302 /** Returns the comparison operator */ 303 public CompareOperator getCompareOp() { 304 return op; 305 } 306 307 /** Returns the expected value */ 308 public byte[] getValue() { 309 return value; 310 } 311 312 /** Returns the filter to check */ 313 public Filter getFilter() { 314 return filter; 315 } 316 317 /** Returns whether this has a filter or not */ 318 public boolean hasFilter() { 319 return filter != null; 320 } 321 322 /** Returns the time range to check */ 323 public TimeRange getTimeRange() { 324 return timeRange; 325 } 326 327 /** Returns the action done if check succeeds */ 328 public Row getAction() { 329 return action; 330 } 331 332 /** Returns whether query metrics are enabled */ 333 public boolean isQueryMetricsEnabled() { 334 return queryMetricsEnabled; 335 } 336}