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.util; 019 020import static org.junit.jupiter.api.Assertions.assertEquals; 021 022import org.apache.hadoop.hbase.HConstants; 023import org.apache.hadoop.hbase.KeyValue; 024import org.apache.hadoop.hbase.PrivateCellUtil; 025import org.apache.hadoop.hbase.testclassification.MiscTests; 026import org.apache.hadoop.hbase.testclassification.SmallTests; 027import org.junit.jupiter.api.BeforeEach; 028import org.junit.jupiter.api.Tag; 029import org.junit.jupiter.api.Test; 030 031@Tag(MiscTests.TAG) 032@Tag(SmallTests.TAG) 033public class TestRowColBloomHashKey { 034 035 private KeyValue kv; 036 private RowColBloomHashKey hashKey; 037 038 @BeforeEach 039 public void setup() { 040 byte[] row = Bytes.toBytes("row_key_test"); 041 byte[] family = Bytes.toBytes("family"); 042 byte[] qualifier = Bytes.toBytes("qualifier"); 043 byte[] value = Bytes.toBytes("1234567890"); 044 kv = new KeyValue(row, family, qualifier, value); 045 hashKey = new RowColBloomHashKey(kv); 046 } 047 048 @Test 049 public void testGet() { 050 final int rowLen = kv.getRowLength(); 051 final int qualLen = kv.getQualifierLength(); 052 053 // Expected virtual layout: 054 // [rowLen(2 bytes)][row bytes][famLen(1 byte, always 0)][qualifier bytes] 055 // [timestamp(8 bytes, HConstants.LATEST_TIMESTAMP)][type(1 byte, KeyValue.Type.Maximum)] 056 final int expectedLength = KeyValue.ROW_LENGTH_SIZE + rowLen + KeyValue.FAMILY_LENGTH_SIZE 057 + qualLen + KeyValue.TIMESTAMP_TYPE_SIZE; 058 assertEquals(expectedLength, hashKey.length()); 059 060 int offset = 0; 061 062 // 1) Row length field: MSB then LSB 063 int msb = hashKey.get(offset++) & 0xFF; 064 int lsb = hashKey.get(offset++) & 0xFF; 065 int decodedRowLen = (msb << 8) | lsb; 066 assertEquals(rowLen, decodedRowLen); 067 068 // 2) Row bytes 069 for (int i = 0; i < rowLen; i++) { 070 int expected = PrivateCellUtil.getRowByte(kv, i) & 0xFF; 071 int actual = hashKey.get(offset++) & 0xFF; 072 assertEquals(expected, actual, "row byte mismatch at i=" + i); 073 } 074 075 // 3) Family length byte 076 assertEquals(0, hashKey.get(offset++) & 0xFF); 077 078 // 4) Qualifier bytes 079 for (int i = 0; i < qualLen; i++) { 080 int expected = PrivateCellUtil.getQualifierByte(kv, i) & 0xFF; 081 int actual = hashKey.get(offset++) & 0xFF; 082 assertEquals(expected, actual, "qualifier byte mismatch at i=" + i); 083 } 084 085 // 5) Timestamp bytes: should match HConstants.LATEST_TIMESTAMP in big-endian 086 // RowColBloomHashKey uses LATEST_TS byte[] from CellHashKey which corresponds to latest 087 // timestamp. 088 long ts = HConstants.LATEST_TIMESTAMP; 089 for (int i = 0; i < KeyValue.TIMESTAMP_SIZE; i++) { 090 // KeyValue timestamp serialization is big-endian 091 int expected = (int) ((ts >>> (8 * (KeyValue.TIMESTAMP_SIZE - 1 - i))) & 0xFF); 092 int actual = hashKey.get(offset++) & 0xFF; 093 assertEquals(expected, actual, "timestamp byte mismatch at i=" + i); 094 } 095 096 // 6) Type byte: should be Maximum 097 assertEquals(KeyValue.Type.Maximum.getCode(), hashKey.get(offset++)); 098 099 // consumed exactly all bytes 100 assertEquals(hashKey.length(), offset); 101 } 102 103 @Test 104 public void testGetIntLE() { 105 for (int i = 0; i <= hashKey.length() - Bytes.SIZEOF_INT; i++) { 106 int expected = expectedIntLEFromGet(i); 107 int actual = hashKey.getIntLE(i); 108 assertEquals(expected, actual, "sequential mismatch at offset=" + i); 109 } 110 } 111 112 private int expectedIntLEFromGet(int offset) { 113 int b0 = hashKey.get(offset) & 0xFF; 114 int b1 = hashKey.get(offset + 1) & 0xFF; 115 int b2 = hashKey.get(offset + 2) & 0xFF; 116 int b3 = hashKey.get(offset + 3) & 0xFF; 117 return (b0) | (b1 << 8) | (b2 << 16) | (b3 << 24); 118 } 119}