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