1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.hbase.util;
19
20 import static org.junit.Assert.*;
21
22 import java.io.FileNotFoundException;
23 import java.io.IOException;
24 import java.util.Arrays;
25
26 import org.apache.commons.logging.Log;
27 import org.apache.commons.logging.LogFactory;
28 import org.apache.hadoop.fs.FileStatus;
29 import org.apache.hadoop.fs.FileSystem;
30 import org.apache.hadoop.fs.Path;
31 import org.apache.hadoop.hbase.*;
32 import org.junit.Test;
33 import org.junit.experimental.categories.Category;
34
35
36
37
38
39
40 @Category(MediumTests.class)
41 public class TestFSTableDescriptors {
42 private static final HBaseTestingUtility UTIL = new HBaseTestingUtility();
43 private static final Log LOG = LogFactory.getLog(TestFSTableDescriptors.class);
44
45 @Test (expected=IllegalArgumentException.class)
46 public void testRegexAgainstOldStyleTableInfo() {
47 Path p = new Path("/tmp", FSTableDescriptors.TABLEINFO_NAME);
48 int i = FSTableDescriptors.getTableInfoSequenceid(p);
49 assertEquals(0, i);
50
51 p = new Path("/tmp", "abc");
52 FSTableDescriptors.getTableInfoSequenceid(p);
53 }
54
55 @Test
56 public void testCreateAndUpdate() throws IOException {
57 Path testdir = UTIL.getDataTestDir("testCreate");
58 HTableDescriptor htd = new HTableDescriptor("testCreate");
59 FileSystem fs = FileSystem.get(UTIL.getConfiguration());
60 assertTrue(FSTableDescriptors.createTableDescriptor(fs, testdir, htd));
61 assertFalse(FSTableDescriptors.createTableDescriptor(fs, testdir, htd));
62 FileStatus [] statuses = fs.listStatus(testdir);
63 assertTrue("statuses.length="+statuses.length, statuses.length == 1);
64 for (int i = 0; i < 10; i++) {
65 FSTableDescriptors.updateHTableDescriptor(fs, testdir, htd);
66 }
67 statuses = fs.listStatus(testdir);
68 assertTrue(statuses.length == 1);
69 Path tmpTableDir = new Path(FSUtils.getTablePath(testdir, htd.getName()), ".tmp");
70 statuses = fs.listStatus(tmpTableDir);
71 assertTrue(statuses.length == 0);
72 }
73
74 @Test
75 public void testSequenceidAdvancesOnTableInfo() throws IOException {
76 Path testdir = UTIL.getDataTestDir("testSequenceidAdvancesOnTableInfo");
77 HTableDescriptor htd = new HTableDescriptor("testSequenceidAdvancesOnTableInfo");
78 FileSystem fs = FileSystem.get(UTIL.getConfiguration());
79 Path p0 = FSTableDescriptors.updateHTableDescriptor(fs, testdir, htd);
80 int i0 = FSTableDescriptors.getTableInfoSequenceid(p0);
81 Path p1 = FSTableDescriptors.updateHTableDescriptor(fs, testdir, htd);
82
83 assertTrue(!fs.exists(p0));
84 int i1 = FSTableDescriptors.getTableInfoSequenceid(p1);
85 assertTrue(i1 == i0 + 1);
86 Path p2 = FSTableDescriptors.updateHTableDescriptor(fs, testdir, htd);
87
88 assertTrue(!fs.exists(p1));
89 int i2 = FSTableDescriptors.getTableInfoSequenceid(p2);
90 assertTrue(i2 == i1 + 1);
91 }
92
93 @Test
94 public void testFormatTableInfoSequenceId() {
95 Path p0 = assertWriteAndReadSequenceid(0);
96
97 StringBuilder sb = new StringBuilder();
98 for (int i = 0; i < FSTableDescriptors.WIDTH_OF_SEQUENCE_ID; i++) {
99 sb.append("0");
100 }
101 assertEquals(FSTableDescriptors.TABLEINFO_NAME + "." + sb.toString(),
102 p0.getName());
103
104 Path p2 = assertWriteAndReadSequenceid(2);
105 Path p10000 = assertWriteAndReadSequenceid(10000);
106
107 Path p = new Path(p0.getParent(), FSTableDescriptors.TABLEINFO_NAME);
108 FileStatus fs = new FileStatus(0, false, 0, 0, 0, p);
109 FileStatus fs0 = new FileStatus(0, false, 0, 0, 0, p0);
110 FileStatus fs2 = new FileStatus(0, false, 0, 0, 0, p2);
111 FileStatus fs10000 = new FileStatus(0, false, 0, 0, 0, p10000);
112 FSTableDescriptors.FileStatusFileNameComparator comparator =
113 new FSTableDescriptors.FileStatusFileNameComparator();
114 assertTrue(comparator.compare(fs, fs0) > 0);
115 assertTrue(comparator.compare(fs0, fs2) > 0);
116 assertTrue(comparator.compare(fs2, fs10000) > 0);
117 }
118
119 private Path assertWriteAndReadSequenceid(final int i) {
120 Path p = FSTableDescriptors.getTableInfoFileName(new Path("/tmp"), i);
121 int ii = FSTableDescriptors.getTableInfoSequenceid(p);
122 assertEquals(i, ii);
123 return p;
124 }
125
126 @Test
127 public void testRemoves() throws IOException {
128 final String name = "testRemoves";
129 FileSystem fs = FileSystem.get(UTIL.getConfiguration());
130
131 Path rootdir = new Path(UTIL.getDataTestDir(), name);
132 TableDescriptors htds = new FSTableDescriptors(fs, rootdir);
133 HTableDescriptor htd = new HTableDescriptor(name);
134 htds.add(htd);
135 assertNotNull(htds.remove(htd.getNameAsString()));
136 assertNull(htds.remove(htd.getNameAsString()));
137 }
138
139 @Test public void testReadingHTDFromFS() throws IOException {
140 final String name = "testReadingHTDFromFS";
141 FileSystem fs = FileSystem.get(UTIL.getConfiguration());
142 HTableDescriptor htd = new HTableDescriptor(name);
143 Path rootdir = UTIL.getDataTestDir(name);
144 createHTDInFS(fs, rootdir, htd);
145 HTableDescriptor htd2 =
146 FSTableDescriptors.getTableDescriptor(fs, rootdir, htd.getNameAsString());
147 assertTrue(htd.equals(htd2));
148 }
149
150 private void createHTDInFS(final FileSystem fs, Path rootdir,
151 final HTableDescriptor htd)
152 throws IOException {
153 FSTableDescriptors.createTableDescriptor(fs, rootdir, htd);
154 }
155
156 @Test public void testHTableDescriptors()
157 throws IOException, InterruptedException {
158 final String name = "testHTableDescriptors";
159 FileSystem fs = FileSystem.get(UTIL.getConfiguration());
160
161 Path rootdir = new Path(UTIL.getDataTestDir(), name);
162 final int count = 10;
163
164 for (int i = 0; i < count; i++) {
165 HTableDescriptor htd = new HTableDescriptor(name + i);
166 createHTDInFS(fs, rootdir, htd);
167 }
168 FSTableDescriptors htds = new FSTableDescriptors(fs, rootdir) {
169 @Override
170 public HTableDescriptor get(byte[] tablename)
171 throws TableExistsException, FileNotFoundException, IOException {
172 LOG.info(Bytes.toString(tablename) + ", cachehits=" + this.cachehits);
173 return super.get(tablename);
174 }
175 };
176 for (int i = 0; i < count; i++) {
177 assertTrue(htds.get(Bytes.toBytes(name + i)) != null);
178 }
179 for (int i = 0; i < count; i++) {
180 assertTrue(htds.get(Bytes.toBytes(name + i)) != null);
181 }
182
183 for (int i = 0; i < count; i++) {
184 HTableDescriptor htd = new HTableDescriptor(name + i);
185 htd.addFamily(new HColumnDescriptor("" + i));
186 FSTableDescriptors.updateHTableDescriptor(fs, rootdir, htd);
187 }
188
189 Thread.sleep(100);
190 for (int i = 0; i < count; i++) {
191 assertTrue(htds.get(Bytes.toBytes(name + i)) != null);
192 }
193 for (int i = 0; i < count; i++) {
194 assertTrue(htds.get(Bytes.toBytes(name + i)) != null);
195 }
196 assertEquals(count * 4, htds.invocations);
197 assertTrue("expected=" + (count * 2) + ", actual=" + htds.cachehits,
198 htds.cachehits >= (count * 2));
199 assertTrue(htds.get(HConstants.ROOT_TABLE_NAME) != null);
200 assertEquals(htds.invocations, count * 4 + 1);
201 assertTrue("expected=" + ((count * 2) + 1) + ", actual=" + htds.cachehits,
202 htds.cachehits >= ((count * 2) + 1));
203 }
204
205 @Test
206 public void testNoSuchTable() throws IOException {
207 final String name = "testNoSuchTable";
208 FileSystem fs = FileSystem.get(UTIL.getConfiguration());
209
210 Path rootdir = new Path(UTIL.getDataTestDir(), name);
211 TableDescriptors htds = new FSTableDescriptors(fs, rootdir);
212 assertNull("There shouldn't be any HTD for this table",
213 htds.get("NoSuchTable"));
214 }
215
216 @Test
217 public void testUpdates() throws IOException {
218 final String name = "testUpdates";
219 FileSystem fs = FileSystem.get(UTIL.getConfiguration());
220
221 Path rootdir = new Path(UTIL.getDataTestDir(), name);
222 TableDescriptors htds = new FSTableDescriptors(fs, rootdir);
223 HTableDescriptor htd = new HTableDescriptor(name);
224 htds.add(htd);
225 htds.add(htd);
226 htds.add(htd);
227 }
228
229 @Test
230 public void testTableInfoFileStatusComparator() {
231 FileStatus bare =
232 new FileStatus(0, false, 0, 0, -1, new Path("/tmp", FSTableDescriptors.TABLEINFO_NAME));
233 FileStatus future =
234 new FileStatus(0, false, 0, 0, -1,
235 new Path("/tmp/tablinfo." + System.currentTimeMillis()));
236 FileStatus farFuture =
237 new FileStatus(0, false, 0, 0, -1,
238 new Path("/tmp/tablinfo." + System.currentTimeMillis() + 1000));
239 FileStatus [] alist = {bare, future, farFuture};
240 FileStatus [] blist = {bare, farFuture, future};
241 FileStatus [] clist = {farFuture, bare, future};
242 FSTableDescriptors.FileStatusFileNameComparator c =
243 new FSTableDescriptors.FileStatusFileNameComparator();
244 Arrays.sort(alist, c);
245 Arrays.sort(blist, c);
246 Arrays.sort(clist, c);
247
248 for (int i = 0; i < alist.length; i++) {
249 assertTrue(alist[i].equals(blist[i]));
250 assertTrue(blist[i].equals(clist[i]));
251 assertTrue(clist[i].equals(i == 0? farFuture: i == 1? future: bare));
252 }
253 }
254
255 @Test
256 public void testReadingArchiveDirectoryFromFS() throws IOException {
257 FileSystem fs = FileSystem.get(UTIL.getConfiguration());
258 try {
259 new FSTableDescriptors(fs, FSUtils.getRootDir(UTIL.getConfiguration()))
260 .get(HConstants.HFILE_ARCHIVE_DIRECTORY);
261 fail("Shouldn't be able to read a table descriptor for the archive directory.");
262 } catch (IOException e) {
263 LOG.debug("Correctly got error when reading a table descriptor from the archive directory: "
264 + e.getMessage());
265 }
266 }
267
268 @org.junit.Rule
269 public org.apache.hadoop.hbase.ResourceCheckerJUnitRule cu =
270 new org.apache.hadoop.hbase.ResourceCheckerJUnitRule();
271 }
272