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.hbase.classification.InterfaceAudience;
22 import org.apache.hadoop.hbase.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
90 public static final TableName BACKUP_TABLE_NAME =
91 valueOf(NamespaceDescriptor.SYSTEM_NAMESPACE_NAME_STR, "backup");
92
93 public static final String OLD_META_STR = ".META.";
94 public static final String OLD_ROOT_STR = "-ROOT-";
95
96
97
98
99
100
101
102 public static final TableName OLD_ROOT_TABLE_NAME = getADummyTableName(OLD_ROOT_STR);
103
104
105
106 public static final TableName OLD_META_TABLE_NAME = getADummyTableName(OLD_META_STR);
107
108 private final byte[] name;
109 private final String nameAsString;
110 private final byte[] namespace;
111 private final String namespaceAsString;
112 private final byte[] qualifier;
113 private final String qualifierAsString;
114 private final boolean systemTable;
115 private final int hashCode;
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136 public static byte [] isLegalFullyQualifiedTableName(final byte[] tableName) {
137 if (tableName == null || tableName.length <= 0) {
138 throw new IllegalArgumentException("Name is null or empty");
139 }
140
141 int namespaceDelimIndex = com.google.common.primitives.Bytes.lastIndexOf(tableName,
142 (byte) NAMESPACE_DELIM);
143 if (namespaceDelimIndex < 0){
144 isLegalTableQualifierName(tableName);
145 } else {
146 isLegalNamespaceName(tableName, 0, namespaceDelimIndex);
147 isLegalTableQualifierName(tableName, namespaceDelimIndex + 1, tableName.length);
148 }
149 return tableName;
150 }
151
152 public static byte [] isLegalTableQualifierName(final byte[] qualifierName) {
153 isLegalTableQualifierName(qualifierName, 0, qualifierName.length, false);
154 return qualifierName;
155 }
156
157 public static byte [] isLegalTableQualifierName(final byte[] qualifierName, boolean isSnapshot) {
158 isLegalTableQualifierName(qualifierName, 0, qualifierName.length, isSnapshot);
159 return qualifierName;
160 }
161
162
163
164
165
166
167
168
169
170
171
172 public static void isLegalTableQualifierName(final byte[] qualifierName,
173 int start,
174 int end) {
175 isLegalTableQualifierName(qualifierName, start, end, false);
176 }
177
178 public static void isLegalTableQualifierName(final byte[] qualifierName,
179 int start,
180 int end,
181 boolean isSnapshot) {
182 if(end - start < 1) {
183 throw new IllegalArgumentException(isSnapshot ? "Snapshot" : "Table" + " qualifier must not be empty");
184 }
185
186 if (qualifierName[start] == '.' || qualifierName[start] == '-') {
187 throw new IllegalArgumentException("Illegal first character <" + qualifierName[start] +
188 "> at 0. " + (isSnapshot ? "Snapshot" : "User-space table") +
189 " qualifiers can only start with 'alphanumeric " +
190 "characters': i.e. [a-zA-Z_0-9]: " +
191 Bytes.toString(qualifierName, start, end));
192 }
193 for (int i = start; i < end; i++) {
194 if (Character.isLetterOrDigit(qualifierName[i]) ||
195 qualifierName[i] == '_' ||
196 qualifierName[i] == '-' ||
197 qualifierName[i] == '.') {
198 continue;
199 }
200 throw new IllegalArgumentException("Illegal character code:" + qualifierName[i] +
201 ", <" + (char) qualifierName[i] + "> at " + i +
202 ". " + (isSnapshot ? "Snapshot" : "User-space table") +
203 " qualifiers can only contain " +
204 "'alphanumeric characters': i.e. [a-zA-Z_0-9-.]: " +
205 Bytes.toString(qualifierName, start, end));
206 }
207 }
208 public static void isLegalNamespaceName(byte[] namespaceName) {
209 isLegalNamespaceName(namespaceName, 0, namespaceName.length);
210 }
211
212
213
214
215 public static void isLegalNamespaceName(final byte[] namespaceName,
216 final int start,
217 final int end) {
218 if(end - start < 1) {
219 throw new IllegalArgumentException("Namespace name must not be empty");
220 }
221 for (int i = start; i < end; i++) {
222 if (Character.isLetterOrDigit(namespaceName[i])|| namespaceName[i] == '_') {
223 continue;
224 }
225 throw new IllegalArgumentException("Illegal character <" + namespaceName[i] +
226 "> at " + i + ". Namespaces can only contain " +
227 "'alphanumeric characters': i.e. [a-zA-Z_0-9]: " + Bytes.toString(namespaceName,
228 start, end));
229 }
230 }
231
232 public byte[] getName() {
233 return name;
234 }
235
236 public String getNameAsString() {
237 return nameAsString;
238 }
239
240 public byte[] getNamespace() {
241 return namespace;
242 }
243
244 public String getNamespaceAsString() {
245 return namespaceAsString;
246 }
247
248
249
250
251
252
253 public String getNameWithNamespaceInclAsString() {
254 if(getNamespaceAsString().equals(NamespaceDescriptor.DEFAULT_NAMESPACE_NAME_STR)) {
255 return NamespaceDescriptor.DEFAULT_NAMESPACE_NAME_STR +
256 TableName.NAMESPACE_DELIM + getNameAsString();
257 }
258 return getNameAsString();
259 }
260
261 public byte[] getQualifier() {
262 return qualifier;
263 }
264
265 public String getQualifierAsString() {
266 return qualifierAsString;
267 }
268
269 public byte[] toBytes() {
270 return name;
271 }
272
273 public boolean isSystemTable() {
274 return systemTable;
275 }
276
277 @Override
278 public String toString() {
279 return nameAsString;
280 }
281
282
283
284
285
286 private TableName(ByteBuffer namespace, ByteBuffer qualifier) throws IllegalArgumentException {
287 this.qualifier = new byte[qualifier.remaining()];
288 qualifier.duplicate().get(this.qualifier);
289 this.qualifierAsString = Bytes.toString(this.qualifier);
290
291 if (qualifierAsString.equals(OLD_ROOT_STR)) {
292 throw new IllegalArgumentException(OLD_ROOT_STR + " has been deprecated.");
293 }
294 if (qualifierAsString.equals(OLD_META_STR)) {
295 throw new IllegalArgumentException(OLD_META_STR + " no longer exists. The table has been " +
296 "renamed to " + META_TABLE_NAME);
297 }
298
299 if (Bytes.equals(NamespaceDescriptor.DEFAULT_NAMESPACE_NAME, namespace)) {
300
301 this.namespace = NamespaceDescriptor.DEFAULT_NAMESPACE_NAME;
302 this.namespaceAsString = NamespaceDescriptor.DEFAULT_NAMESPACE_NAME_STR;
303 this.systemTable = false;
304
305
306 this.nameAsString = qualifierAsString;
307 this.name = this.qualifier;
308 } else {
309 if (Bytes.equals(NamespaceDescriptor.SYSTEM_NAMESPACE_NAME, namespace)) {
310 this.namespace = NamespaceDescriptor.SYSTEM_NAMESPACE_NAME;
311 this.namespaceAsString = NamespaceDescriptor.SYSTEM_NAMESPACE_NAME_STR;
312 this.systemTable = true;
313 } else {
314 this.namespace = new byte[namespace.remaining()];
315 namespace.duplicate().get(this.namespace);
316 this.namespaceAsString = Bytes.toString(this.namespace);
317 this.systemTable = false;
318 }
319 this.nameAsString = namespaceAsString + NAMESPACE_DELIM + qualifierAsString;
320 this.name = Bytes.toBytes(nameAsString);
321 }
322
323 this.hashCode = nameAsString.hashCode();
324
325 isLegalNamespaceName(this.namespace);
326 isLegalTableQualifierName(this.qualifier);
327 }
328
329
330
331
332 private TableName(String qualifier) {
333 this.qualifier = Bytes.toBytes(qualifier);
334 this.qualifierAsString = qualifier;
335
336 this.namespace = NamespaceDescriptor.SYSTEM_NAMESPACE_NAME;
337 this.namespaceAsString = NamespaceDescriptor.SYSTEM_NAMESPACE_NAME_STR;
338 this.systemTable = true;
339
340
341
342 this.nameAsString = namespaceAsString + NAMESPACE_DELIM + qualifierAsString;
343 this.name = this.qualifier;
344
345 this.hashCode = nameAsString.hashCode();
346 }
347
348
349
350
351
352
353
354
355 private static TableName createTableNameIfNecessary(ByteBuffer bns, ByteBuffer qns) {
356 for (TableName tn : tableCache) {
357 if (Bytes.equals(tn.getQualifier(), qns) && Bytes.equals(tn.getNamespace(), bns)) {
358 return tn;
359 }
360 }
361
362 TableName newTable = new TableName(bns, qns);
363 if (tableCache.add(newTable)) {
364 return newTable;
365 }
366
367
368 for (TableName tn : tableCache) {
369 if (Bytes.equals(tn.getQualifier(), qns) && Bytes.equals(tn.getNamespace(), bns)) {
370 return tn;
371 }
372 }
373
374 throw new IllegalStateException(newTable + " was supposed to be in the cache");
375 }
376
377
378
379
380
381
382
383 private static TableName getADummyTableName(String qualifier) {
384 return new TableName(qualifier);
385 }
386
387
388 public static TableName valueOf(String namespaceAsString, String qualifierAsString) {
389 if (namespaceAsString == null || namespaceAsString.length() < 1) {
390 namespaceAsString = NamespaceDescriptor.DEFAULT_NAMESPACE_NAME_STR;
391 }
392
393 for (TableName tn : tableCache) {
394 if (qualifierAsString.equals(tn.getQualifierAsString()) &&
395 namespaceAsString.equals(tn.getNameAsString())) {
396 return tn;
397 }
398 }
399
400 return createTableNameIfNecessary(
401 ByteBuffer.wrap(Bytes.toBytes(namespaceAsString)),
402 ByteBuffer.wrap(Bytes.toBytes(qualifierAsString)));
403 }
404
405
406
407
408
409
410
411 public static TableName valueOf(byte[] fullName) throws IllegalArgumentException{
412 for (TableName tn : tableCache) {
413 if (Arrays.equals(tn.getName(), fullName)) {
414 return tn;
415 }
416 }
417
418 int namespaceDelimIndex = com.google.common.primitives.Bytes.lastIndexOf(fullName,
419 (byte) NAMESPACE_DELIM);
420
421 if (namespaceDelimIndex < 0) {
422 return createTableNameIfNecessary(
423 ByteBuffer.wrap(NamespaceDescriptor.DEFAULT_NAMESPACE_NAME),
424 ByteBuffer.wrap(fullName));
425 } else {
426 return createTableNameIfNecessary(
427 ByteBuffer.wrap(fullName, 0, namespaceDelimIndex),
428 ByteBuffer.wrap(fullName, namespaceDelimIndex + 1,
429 fullName.length - (namespaceDelimIndex + 1)));
430 }
431 }
432
433
434
435
436
437
438 public static TableName valueOf(String name) {
439 for (TableName tn : tableCache) {
440 if (name.equals(tn.getNameAsString())) {
441 return tn;
442 }
443 }
444
445 int namespaceDelimIndex = name.indexOf(NAMESPACE_DELIM);
446 byte[] nameB = Bytes.toBytes(name);
447
448 if (namespaceDelimIndex < 0) {
449 return createTableNameIfNecessary(
450 ByteBuffer.wrap(NamespaceDescriptor.DEFAULT_NAMESPACE_NAME),
451 ByteBuffer.wrap(nameB));
452 } else {
453 return createTableNameIfNecessary(
454 ByteBuffer.wrap(nameB, 0, namespaceDelimIndex),
455 ByteBuffer.wrap(nameB, namespaceDelimIndex + 1,
456 nameB.length - (namespaceDelimIndex + 1)));
457 }
458 }
459
460
461 public static TableName valueOf(byte[] namespace, byte[] qualifier) {
462 if (namespace == null || namespace.length < 1) {
463 namespace = NamespaceDescriptor.DEFAULT_NAMESPACE_NAME;
464 }
465
466 for (TableName tn : tableCache) {
467 if (Arrays.equals(tn.getQualifier(), qualifier) &&
468 Arrays.equals(tn.getNamespace(), namespace)) {
469 return tn;
470 }
471 }
472
473 return createTableNameIfNecessary(
474 ByteBuffer.wrap(namespace), ByteBuffer.wrap(qualifier));
475 }
476
477 public static TableName valueOf(ByteBuffer namespace, ByteBuffer qualifier) {
478 if (namespace == null || namespace.remaining() < 1) {
479 return createTableNameIfNecessary(
480 ByteBuffer.wrap(NamespaceDescriptor.DEFAULT_NAMESPACE_NAME), qualifier);
481 }
482
483 return createTableNameIfNecessary(namespace, qualifier);
484 }
485
486 @Override
487 public boolean equals(Object o) {
488 if (this == o) return true;
489 if (o == null || getClass() != o.getClass()) return false;
490
491 TableName tableName = (TableName) o;
492
493 return o.hashCode() == hashCode && nameAsString.equals(tableName.nameAsString);
494 }
495
496 @Override
497 public int hashCode() {
498 return hashCode;
499 }
500
501
502
503
504 @Override
505 public int compareTo(TableName tableName) {
506 if (this == tableName) return 0;
507 if (this.hashCode < tableName.hashCode()) {
508 return -1;
509 }
510 if (this.hashCode > tableName.hashCode()) {
511 return 1;
512 }
513 return this.nameAsString.compareTo(tableName.getNameAsString());
514 }
515
516
517
518
519
520
521
522
523 @InterfaceAudience.Private
524 @Deprecated
525 public KVComparator getRowComparator() {
526 if(TableName.META_TABLE_NAME.equals(this)) {
527 return KeyValue.META_COMPARATOR;
528 }
529 return KeyValue.COMPARATOR;
530 }
531 }