当要检查的行与 Put 的行不同时,checkAndPut 在什么情况下有用?

In what case checkAndPut is useful when row to be checked is different from the row of the Put?

这是 checkAndPut API

public boolean checkAndPut(byte[] row, byte[] family, byte[] qualifier, byte[] value, Put put)

如果我的理解是正确的,row参数可以与put的行不同。但这为什么有用?我认为 checkAndPut 就像硬件架构中的 CompareAndSwap(CAS) 操作一样。 CAS 正在比较和设置单个变量。但是 checkAndPut 似乎支持对不同行的操作。这有帮助吗?或者我们需要保证 row 实际上与 put?

的行相同

checkAndPut() 是 CAS 的 HBase 变体,现在已弃用,应改用 checkAndMutate。 正如 javadoc 中指定的那样,API 自动检查 row/family/qualifier 值是否与预期值匹配。如果是,它会添加看跌期权。如果传递的值为空,则检查是否缺少列(即:不存在)。

让我们以列族 'cf1' 为例 table 't1' 并了解以下场景中的行为 -

创建要插入的行

val put = new Put(Bytes.toBytes("r1"))
put.addColumn(Bytes.toBytes("cf1"), Bytes.toBytes("q1"), Bytes.toBytes("v1"))

案例 1 - table

中不存在行、列族或列

Result - 插入一条新记录,res = true

var res = table.checkAndPut(Bytes.toBytes("r1"), Bytes.toBytes("cf1"), Bytes.toBytes("q1"), null, put)

案例 2 - 重新插入在案例 1 中插入的相同记录

Result - 没有更新插入发生,因为该列已经存在,res = false

res = table.checkAndPut(Bytes.toBytes("r1"), Bytes.toBytes("cf1"), Bytes.toBytes("q1"), null, put)

案例 3 - 添加一个新的行键 r2 cf1:q1,而 Put 仍然设置为 rowkey = r1.

Result - 没有更新插入发生,我们得到一个异常 - "Action's getRow must match the passed row",这意味着在 checkAndPut 中设置的行键预计与 Put 中的行键相同,并且这个 API 正在按顺序检查行、列族和列限定符是否存在,并对照 Put

中指定的值
res = table.checkAndPut(Bytes.toBytes("r2"), Bytes.toBytes("cf1"), Bytes.toBytes("q1"), null, put)

Case 4 - row key r1 column q1 增加一个新的column family cf2,同时Put仍然设置为rowkey = r1, column family cf1.

Result - 没有更新插入发生,我们得到一个异常 - "Column family cf2 does not exist in region t1,,1524474825488.a1f7efa76e78f38d64f95b63222cbfa8. in table 't1'....."

res = table.checkAndPut(Bytes.toBytes("r1"), Bytes.toBytes("cf2"), Bytes.toBytes("q1"), null, put)

案例 5 - 我们没有检查 q1,而是在 checkAndPut()

中检查 q2 是否存在

Result - 这里 API 将检查列 q2 是否存在,在我们的例子中不存在,因此相同的列 q1 将得到更新,如 Put仍然设置为值v1,只有q1的timestamp/version会改变,res = true

res = table.checkAndPut(Bytes.toBytes("r1"), Bytes.toBytes("cf1"), Bytes.toBytes("q2"), null, put)

案例 6 - 在前面的所有示例中,第 4 个参数都设置为 null,这里我们指定了实际值

Result - checkAndPut 将为 q1 指定的值与 Put 进行比较,因为它比较等于插入发生,res = true

res = table.checkAndPut(Bytes.toBytes("r1"), Bytes.toBytes("cf1"), Bytes.toBytes("q1"), Bytes.toBytes("v1"), put)

案例 3 和案例 4 回答了您问题的最后一部分。

从可用性的角度来看,我认为这个 API 在同一 row/column 上可能发生大量并发更新的情况下很有用,为了避免任何冲突和过时的数据,我们读取验证然后写入,像 OCC - https://en.wikipedia.org/wiki/Optimistic_concurrency_control#OCC_phases

要对多个 rows/columns 执行更新插入,应该使用 checkAndMutate。 [检查 - ]

希望对您有所帮助。