1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.tikv.common.codec;
19
20 import java.util.Arrays;
21 import org.tikv.common.exception.InvalidCodecFormatException;
22
23 public class RowV2 {
24
25 public static int CODEC_VER = 0x80;
26
27
28 boolean large;
29 int numNotNullCols;
30 int numNullCols;
31 byte[] colIDs;
32 int[] offsets;
33 byte[] data;
34
35 int[] colIDs32;
36 int[] offsets32;
37
38 private RowV2(byte[] rowData) {
39 fromBytes(rowData);
40 }
41
42 public static RowV2 createNew(byte[] rowData) {
43 return new RowV2(rowData);
44 }
45
46 public static RowV2 createEmpty() {
47 return new RowV2(false, 0, 0);
48 }
49
50 private RowV2(boolean large, int numNotNullCols, int numNullCols) {
51 this.large = large;
52 this.numNotNullCols = numNotNullCols;
53 this.numNullCols = numNullCols;
54 }
55
56 public byte[] getData(int i) {
57 int start = 0, end = 0;
58 if (this.large) {
59 if (i > 0) {
60 start = this.offsets32[i - 1];
61 }
62 end = this.offsets32[i];
63 } else {
64 if (i > 0) {
65 start = this.offsets[i - 1];
66 }
67 end = this.offsets[i];
68 }
69 return Arrays.copyOfRange(this.data, start, end);
70 }
71
72 private void fromBytes(byte[] rowData) {
73 CodecDataInputLittleEndian cdi = new CodecDataInputLittleEndian(rowData);
74 if (cdi.readUnsignedByte() != CODEC_VER) {
75 throw new InvalidCodecFormatException("invalid codec version");
76 }
77 this.large = (cdi.readUnsignedByte() & 1) > 0;
78 this.numNotNullCols = cdi.readUnsignedShort();
79 this.numNullCols = cdi.readUnsignedShort();
80 int cursor = 6;
81 if (this.large) {
82 int numCols = this.numNotNullCols + this.numNullCols;
83 int colIDsLen = numCols * 4;
84 this.colIDs32 = new int[numCols];
85 for (int i = 0; i < numCols; i++) {
86 this.colIDs32[i] = cdi.readInt();
87 }
88 cursor += colIDsLen;
89 numCols = this.numNotNullCols;
90 int offsetsLen = numCols * 4;
91 this.offsets32 = new int[numCols];
92 for (int i = 0; i < numCols; i++) {
93 this.offsets32[i] = cdi.readInt();
94 }
95 cursor += offsetsLen;
96 } else {
97 int numCols = this.numNotNullCols + this.numNullCols;
98 int colIDsLen = numCols;
99 this.colIDs = new byte[numCols];
100 cdi.readFully(this.colIDs, 0, numCols);
101 cursor += colIDsLen;
102 numCols = this.numNotNullCols;
103 int offsetsLen = numCols * 2;
104 this.offsets = new int[numCols];
105 for (int i = 0; i < numCols; i++) {
106 this.offsets[i] = cdi.readUnsignedShort();
107 }
108 cursor += offsetsLen;
109 }
110 this.data = Arrays.copyOfRange(rowData, cursor, rowData.length);
111 }
112
113 private void writeShortArray(CodecDataOutput cdo, int[] arr) {
114 for (int value : arr) {
115 cdo.writeShort(value);
116 }
117 }
118
119 private void writeIntArray(CodecDataOutput cdo, int[] arr) {
120 for (int value : arr) {
121 cdo.writeInt(value);
122 }
123 }
124
125 public byte[] toBytes() {
126 CodecDataOutputLittleEndian cdo = new CodecDataOutputLittleEndian();
127 cdo.write(CODEC_VER);
128 cdo.write(this.large ? 1 : 0);
129 cdo.writeShort(this.numNotNullCols);
130 cdo.writeShort(this.numNullCols);
131 if (this.large) {
132 writeIntArray(cdo, this.colIDs32);
133 writeIntArray(cdo, this.offsets32);
134 } else {
135 cdo.write(this.colIDs);
136 writeShortArray(cdo, this.offsets);
137 }
138 cdo.write(this.data);
139 return cdo.toBytes();
140 }
141
142 private int binarySearch(int i, int j, long colID) {
143 while (i < j) {
144 int h = (int) ((i + (long) j) >> 1);
145
146 long v;
147 if (this.large) {
148 v = this.colIDs32[h];
149 } else {
150 v = this.colIDs[h] & 0xFF;
151 }
152 if (v < colID) {
153 i = h + 1;
154 } else if (v > colID) {
155 j = h;
156 } else {
157 return h;
158 }
159 }
160 return -1;
161 }
162
163 public ColIDSearchResult findColID(long colID) {
164 int i = 0, j = this.numNotNullCols;
165 ColIDSearchResult result = new ColIDSearchResult(-1, false, false);
166 result.idx = binarySearch(i, j, colID);
167 if (result.idx != -1) {
168 return result;
169 }
170
171
172 i = this.numNotNullCols;
173 j = this.numNotNullCols + this.numNullCols;
174 int id = binarySearch(i, j, colID);
175 if (id != -1) {
176
177 result.isNull = true;
178 } else {
179 result.notFound = true;
180 }
181 return result;
182 }
183
184 public void initColIDs() {
185 int numCols = this.numNotNullCols + this.numNullCols;
186 this.colIDs = new byte[numCols];
187 }
188
189 public void initColIDs32() {
190 int numCols = this.numNotNullCols + this.numNullCols;
191 this.colIDs32 = new int[numCols];
192 }
193
194 public void initOffsets() {
195 this.offsets = new int[this.numNotNullCols];
196 }
197
198 public void initOffsets32() {
199 this.offsets32 = new int[this.numNotNullCols];
200 }
201
202 public static class ColIDSearchResult {
203 int idx;
204 boolean isNull;
205 boolean notFound;
206
207 private ColIDSearchResult(int idx, boolean isNull, boolean notFound) {
208 this.idx = idx;
209 this.isNull = isNull;
210 this.notFound = notFound;
211 }
212 }
213 }