1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.tikv.common.key;
19
20 import static java.util.Objects.requireNonNull;
21 import static org.tikv.common.codec.KeyUtils.formatBytes;
22
23 import com.google.common.primitives.Bytes;
24 import com.google.protobuf.ByteString;
25 import java.io.Serializable;
26 import java.util.Arrays;
27 import javax.annotation.Nonnull;
28 import org.tikv.common.codec.CodecDataOutput;
29 import org.tikv.common.types.DataType;
30 import org.tikv.common.util.FastByteComparisons;
31
32 public class Key implements Comparable<Key>, Serializable {
33 public static final Key EMPTY = createEmpty();
34 public static final Key NULL = createNull();
35 public static final Key MIN = createTypelessMin();
36 public static final Key MAX = createTypelessMax();
37 protected static final byte[] TBL_PREFIX = new byte[] {'t'};
38 protected final byte[] value;
39 protected final int infFlag;
40
41 private Key(byte[] value, boolean negative) {
42 this.value = requireNonNull(value, "value is null");
43 this.infFlag = (value.length == 0 ? 1 : 0) * (negative ? -1 : 1);
44 }
45
46 protected Key(byte[] value) {
47 this(value, false);
48 }
49
50 public static Key toRawKey(ByteString bytes, boolean negative) {
51 return new Key(bytes.toByteArray(), negative);
52 }
53
54 public static Key toRawKey(ByteString bytes) {
55 return new Key(bytes.toByteArray());
56 }
57
58 public static Key toRawKey(byte[] bytes, boolean negative) {
59 return new Key(bytes, negative);
60 }
61
62 public static Key toRawKey(byte[] bytes) {
63 return new Key(bytes);
64 }
65
66 private static Key createNull() {
67 CodecDataOutput cdo = new CodecDataOutput();
68 DataType.encodeNull(cdo);
69 return new Key(cdo.toBytes()) {
70 @Override
71 public String toString() {
72 return "null";
73 }
74 };
75 }
76
77 private static Key createEmpty() {
78 return new Key(new byte[0]) {
79 @Override
80 public Key next() {
81 return this;
82 }
83
84 @Override
85 public String toString() {
86 return "EMPTY";
87 }
88 };
89 }
90
91 private static Key createTypelessMin() {
92 CodecDataOutput cdo = new CodecDataOutput();
93 DataType.encodeIndex(cdo);
94 return new Key(cdo.toBytes()) {
95 @Override
96 public String toString() {
97 return "MIN";
98 }
99 };
100 }
101
102 private static Key createTypelessMax() {
103 CodecDataOutput cdo = new CodecDataOutput();
104 DataType.encodeMaxValue(cdo);
105 return new Key(cdo.toBytes()) {
106 @Override
107 public String toString() {
108 return "MAX";
109 }
110 };
111 }
112
113
114
115
116
117
118
119
120
121 static byte[] prefixNext(byte[] value) {
122 int i;
123 byte[] newVal = Arrays.copyOf(value, value.length);
124 for (i = newVal.length - 1; i >= 0; i--) {
125 newVal[i]++;
126 if (newVal[i] != 0) {
127 break;
128 }
129 }
130 if (i == -1) {
131 return Arrays.copyOf(value, value.length + 1);
132 } else {
133 return newVal;
134 }
135 }
136
137
138
139
140
141
142 public Key next() {
143 return toRawKey(Arrays.copyOf(value, value.length + 1));
144 }
145
146
147
148
149
150
151
152 public Key nextPrefix() {
153 return toRawKey(prefixNext(value));
154 }
155
156 @Override
157 public int compareTo(@Nonnull Key other) {
158 if ((this.infFlag | other.infFlag) != 0) {
159 return this.infFlag - other.infFlag;
160 }
161 return FastByteComparisons.compareTo(value, other.value);
162 }
163
164 @Override
165 public boolean equals(Object other) {
166 if (other == this) {
167 return true;
168 }
169 if (other instanceof Key) {
170 return compareTo((Key) other) == 0;
171 } else {
172 return false;
173 }
174 }
175
176 public Key append(Key other) {
177 if (other == null) {
178 return this;
179 }
180 return Key.toRawKey(Bytes.concat(getBytes(), other.getBytes()));
181 }
182
183 @Override
184 public int hashCode() {
185 return Arrays.hashCode(value);
186 }
187
188 public byte[] getBytes() {
189 return value;
190 }
191
192 public ByteString toByteString() {
193 return ByteString.copyFrom(value);
194 }
195
196 public int getInfFlag() {
197 return infFlag;
198 }
199
200 @Override
201 public String toString() {
202 if (infFlag < 0) {
203 return "-INF";
204 } else if (infFlag > 0) {
205 return "+INF";
206 } else {
207 return String.format("{%s}", formatBytes(value));
208 }
209 }
210 }