1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase;
20
21 import org.apache.hadoop.classification.InterfaceAudience;
22 import org.apache.hadoop.classification.InterfaceStability;
23 import org.apache.hadoop.hbase.KeyValue.KVComparator;
24 import org.apache.hadoop.hbase.util.Bytes;
25
26 import java.nio.ByteBuffer;
27 import java.util.Arrays;
28 import java.util.Set;
29 import java.util.concurrent.CopyOnWriteArraySet;
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55 @InterfaceAudience.Public
56 @InterfaceStability.Evolving
57 public final class TableName implements Comparable<TableName> {
58
59
60 private static final Set<TableName> tableCache = new CopyOnWriteArraySet<TableName>();
61
62
63
64 public final static char NAMESPACE_DELIM = ':';
65
66
67
68
69
70 public static final String VALID_NAMESPACE_REGEX =
71 "(?:[a-zA-Z_0-9]+)";
72
73 public static final String VALID_TABLE_QUALIFIER_REGEX =
74 "(?:[a-zA-Z_0-9][a-zA-Z_0-9-.]*)";
75
76
77 public static final String VALID_USER_TABLE_REGEX =
78 "(?:(?:(?:"+VALID_NAMESPACE_REGEX+"\\"+NAMESPACE_DELIM+")?)" +
79 "(?:"+VALID_TABLE_QUALIFIER_REGEX+"))";
80
81
82 public static final TableName META_TABLE_NAME =
83 valueOf(NamespaceDescriptor.SYSTEM_NAMESPACE_NAME_STR, "meta");
84
85
86 public static final TableName NAMESPACE_TABLE_NAME =
87 valueOf(NamespaceDescriptor.SYSTEM_NAMESPACE_NAME_STR, "namespace");
88
89 public static final String OLD_META_STR = ".META.";
90 public static final String OLD_ROOT_STR = "-ROOT-";
91
92
93
94
95
96
97
98 public static final TableName OLD_ROOT_TABLE_NAME = getADummyTableName(OLD_ROOT_STR);
99
100
101
102 public static final TableName OLD_META_TABLE_NAME = getADummyTableName(OLD_META_STR);
103
104 private final byte[] name;
105 private final String nameAsString;
106 private final byte[] namespace;
107 private final String namespaceAsString;
108 private final byte[] qualifier;
109 private final String qualifierAsString;
110 private final boolean systemTable;
111 private final int hashCode;
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132 public static byte [] isLegalFullyQualifiedTableName(final byte[] tableName) {
133 if (tableName == null || tableName.length <= 0) {
134 throw new IllegalArgumentException("Name is null or empty");
135 }
136
137 int namespaceDelimIndex = com.google.common.primitives.Bytes.lastIndexOf(tableName,
138 (byte) NAMESPACE_DELIM);
139 if (namespaceDelimIndex == 0 || namespaceDelimIndex == -1){
140 isLegalTableQualifierName(tableName);
141 } else {
142 isLegalNamespaceName(tableName, 0, namespaceDelimIndex);
143 isLegalTableQualifierName(tableName, namespaceDelimIndex + 1, tableName.length);
144 }
145 return tableName;
146 }
147
148 public static byte [] isLegalTableQualifierName(final byte[] qualifierName){
149 isLegalTableQualifierName(qualifierName, 0, qualifierName.length);
150 return qualifierName;
151 }
152
153
154
155
156
157
158
159
160
161
162 public static void isLegalTableQualifierName(final byte[] qualifierName,
163 int start,
164 int end){
165 if(end - start < 1) {
166 throw new IllegalArgumentException("Table qualifier must not be empty");
167 }
168
169 if (qualifierName[start] == '.' || qualifierName[start] == '-') {
170 throw new IllegalArgumentException("Illegal first character <" + qualifierName[0] +
171 "> at 0. Namespaces can only start with alphanumeric " +
172 "characters': i.e. [a-zA-Z_0-9]: " + Bytes.toString(qualifierName));
173 }
174 for (int i = start; i < end; i++) {
175 if (Character.isLetterOrDigit(qualifierName[i]) ||
176 qualifierName[i] == '_' ||
177 qualifierName[i] == '-' ||
178 qualifierName[i] == '.') {
179 continue;
180 }
181 throw new IllegalArgumentException("Illegal character code:" + qualifierName[i] +
182 ", <" + (char) qualifierName[i] + "> at " + i +
183 ". User-space table qualifiers can only contain " +
184 "'alphanumeric characters': i.e. [a-zA-Z_0-9-.]: " +
185 Bytes.toString(qualifierName, start, end));
186 }
187 }
188
189 public static void isLegalNamespaceName(byte[] namespaceName) {
190 isLegalNamespaceName(namespaceName, 0, namespaceName.length);
191 }
192
193
194
195
196 public static void isLegalNamespaceName(byte[] namespaceName, int offset, int length) {
197 for (int i = offset; i < length; i++) {
198 if (Character.isLetterOrDigit(namespaceName[i])|| namespaceName[i] == '_') {
199 continue;
200 }
201 throw new IllegalArgumentException("Illegal character <" + namespaceName[i] +
202 "> at " + i + ". Namespaces can only contain " +
203 "'alphanumeric characters': i.e. [a-zA-Z_0-9]: " + Bytes.toString(namespaceName,
204 offset, length));
205 }
206 }
207
208 public byte[] getName() {
209 return name;
210 }
211
212 public String getNameAsString() {
213 return nameAsString;
214 }
215
216 public byte[] getNamespace() {
217 return namespace;
218 }
219
220 public String getNamespaceAsString() {
221 return namespaceAsString;
222 }
223
224 public byte[] getQualifier() {
225 return qualifier;
226 }
227
228 public String getQualifierAsString() {
229 return qualifierAsString;
230 }
231
232 public byte[] toBytes() {
233 return name;
234 }
235
236 public boolean isSystemTable() {
237 return systemTable;
238 }
239
240 @Override
241 public String toString() {
242 return nameAsString;
243 }
244
245
246
247
248
249 private TableName(ByteBuffer namespace, ByteBuffer qualifier) throws IllegalArgumentException {
250 this.qualifier = new byte[qualifier.remaining()];
251 qualifier.duplicate().get(this.qualifier);
252 this.qualifierAsString = Bytes.toString(this.qualifier);
253
254 if (qualifierAsString.equals(OLD_ROOT_STR)) {
255 throw new IllegalArgumentException(OLD_ROOT_STR + " has been deprecated.");
256 }
257 if (qualifierAsString.equals(OLD_META_STR)) {
258 throw new IllegalArgumentException(OLD_META_STR + " no longer exists. The table has been " +
259 "renamed to " + META_TABLE_NAME);
260 }
261
262 if (Bytes.equals(NamespaceDescriptor.DEFAULT_NAMESPACE_NAME, namespace)) {
263
264 this.namespace = NamespaceDescriptor.DEFAULT_NAMESPACE_NAME;
265 this.namespaceAsString = NamespaceDescriptor.DEFAULT_NAMESPACE_NAME_STR;
266 this.systemTable = false;
267
268
269 this.nameAsString = qualifierAsString;
270 this.name = this.qualifier;
271 } else {
272 if (Bytes.equals(NamespaceDescriptor.SYSTEM_NAMESPACE_NAME, namespace)) {
273 this.namespace = NamespaceDescriptor.SYSTEM_NAMESPACE_NAME;
274 this.namespaceAsString = NamespaceDescriptor.SYSTEM_NAMESPACE_NAME_STR;
275 this.systemTable = true;
276 } else {
277 this.namespace = new byte[namespace.remaining()];
278 namespace.duplicate().get(this.namespace);
279 this.namespaceAsString = Bytes.toString(this.namespace);
280 this.systemTable = false;
281 }
282 this.nameAsString = namespaceAsString + NAMESPACE_DELIM + qualifierAsString;
283 this.name = Bytes.toBytes(nameAsString);
284 }
285
286 this.hashCode = nameAsString.hashCode();
287
288 isLegalNamespaceName(this.namespace);
289 isLegalTableQualifierName(this.qualifier);
290 }
291
292
293
294
295 private TableName(String qualifier) {
296 this.qualifier = Bytes.toBytes(qualifier);
297 this.qualifierAsString = qualifier;
298
299 this.namespace = NamespaceDescriptor.SYSTEM_NAMESPACE_NAME;
300 this.namespaceAsString = NamespaceDescriptor.SYSTEM_NAMESPACE_NAME_STR;
301 this.systemTable = true;
302
303
304
305 this.nameAsString = namespaceAsString + NAMESPACE_DELIM + qualifierAsString;
306 this.name = this.qualifier;
307
308 this.hashCode = nameAsString.hashCode();
309 }
310
311
312
313
314
315
316
317
318 private static TableName createTableNameIfNecessary(ByteBuffer bns, ByteBuffer qns) {
319 for (TableName tn : tableCache) {
320 if (Bytes.equals(tn.getQualifier(), qns) && Bytes.equals(tn.getNamespace(), bns)) {
321 return tn;
322 }
323 }
324
325 TableName newTable = new TableName(bns, qns);
326 if (tableCache.add(newTable)) {
327 return newTable;
328 }
329
330
331 for (TableName tn : tableCache) {
332 if (Bytes.equals(tn.getQualifier(), qns) && Bytes.equals(tn.getNamespace(), bns)) {
333 return tn;
334 }
335 }
336
337 throw new IllegalStateException(newTable + " was supposed to be in the cache");
338 }
339
340
341
342
343
344
345
346 private static TableName getADummyTableName(String qualifier) {
347 return new TableName(qualifier);
348 }
349
350
351 public static TableName valueOf(String namespaceAsString, String qualifierAsString) {
352 if (namespaceAsString == null || namespaceAsString.length() < 1) {
353 namespaceAsString = NamespaceDescriptor.DEFAULT_NAMESPACE_NAME_STR;
354 }
355
356 for (TableName tn : tableCache) {
357 if (qualifierAsString.equals(tn.getQualifierAsString()) &&
358 namespaceAsString.equals(tn.getNameAsString())) {
359 return tn;
360 }
361 }
362
363 return createTableNameIfNecessary(
364 ByteBuffer.wrap(Bytes.toBytes(namespaceAsString)),
365 ByteBuffer.wrap(Bytes.toBytes(qualifierAsString)));
366 }
367
368
369
370
371
372
373
374 public static TableName valueOf(byte[] fullName) throws IllegalArgumentException{
375 for (TableName tn : tableCache) {
376 if (Arrays.equals(tn.getName(), fullName)) {
377 return tn;
378 }
379 }
380
381 int namespaceDelimIndex = com.google.common.primitives.Bytes.lastIndexOf(fullName,
382 (byte) NAMESPACE_DELIM);
383
384 if (namespaceDelimIndex < 0) {
385 return createTableNameIfNecessary(
386 ByteBuffer.wrap(NamespaceDescriptor.DEFAULT_NAMESPACE_NAME),
387 ByteBuffer.wrap(fullName));
388 } else {
389 return createTableNameIfNecessary(
390 ByteBuffer.wrap(fullName, 0, namespaceDelimIndex),
391 ByteBuffer.wrap(fullName, namespaceDelimIndex + 1,
392 fullName.length - (namespaceDelimIndex + 1)));
393 }
394 }
395
396
397
398
399
400
401 public static TableName valueOf(String name) {
402 for (TableName tn : tableCache) {
403 if (name.equals(tn.getNameAsString())) {
404 return tn;
405 }
406 }
407
408 int namespaceDelimIndex = name.indexOf(NAMESPACE_DELIM);
409 byte[] nameB = Bytes.toBytes(name);
410
411 if (namespaceDelimIndex < 0) {
412 return createTableNameIfNecessary(
413 ByteBuffer.wrap(NamespaceDescriptor.DEFAULT_NAMESPACE_NAME),
414 ByteBuffer.wrap(nameB));
415 } else {
416 return createTableNameIfNecessary(
417 ByteBuffer.wrap(nameB, 0, namespaceDelimIndex),
418 ByteBuffer.wrap(nameB, namespaceDelimIndex + 1,
419 nameB.length - (namespaceDelimIndex + 1)));
420 }
421 }
422
423
424 public static TableName valueOf(byte[] namespace, byte[] qualifier) {
425 if (namespace == null || namespace.length < 1) {
426 namespace = NamespaceDescriptor.DEFAULT_NAMESPACE_NAME;
427 }
428
429 for (TableName tn : tableCache) {
430 if (Arrays.equals(tn.getQualifier(), namespace) &&
431 Arrays.equals(tn.getNamespace(), namespace)) {
432 return tn;
433 }
434 }
435
436 return createTableNameIfNecessary(
437 ByteBuffer.wrap(namespace), ByteBuffer.wrap(qualifier));
438 }
439
440 public static TableName valueOf(ByteBuffer namespace, ByteBuffer qualifier) {
441 if (namespace == null || namespace.remaining() < 1) {
442 return createTableNameIfNecessary(
443 ByteBuffer.wrap(NamespaceDescriptor.DEFAULT_NAMESPACE_NAME), qualifier);
444 }
445
446 return createTableNameIfNecessary(namespace, qualifier);
447 }
448
449 @Override
450 public boolean equals(Object o) {
451 if (this == o) return true;
452 if (o == null || getClass() != o.getClass()) return false;
453
454 TableName tableName = (TableName) o;
455
456 return o.hashCode() == hashCode && nameAsString.equals(tableName.nameAsString);
457 }
458
459 @Override
460 public int hashCode() {
461 return hashCode;
462 }
463
464
465
466
467 @Override
468 public int compareTo(TableName tableName) {
469 if (this == tableName) return 0;
470 if (this.hashCode < tableName.hashCode()) {
471 return -1;
472 }
473 if (this.hashCode > tableName.hashCode()) {
474 return 1;
475 }
476 return this.nameAsString.compareTo(tableName.getNameAsString());
477 }
478
479
480
481
482
483
484 public KVComparator getRowComparator() {
485 if(TableName.META_TABLE_NAME.equals(this)) {
486 return KeyValue.META_COMPARATOR;
487 }
488 return KeyValue.COMPARATOR;
489 }
490 }