1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.apache.hadoop.hbase.wal;
22
23 import java.io.IOException;
24 import java.util.Arrays;
25 import java.io.InterruptedIOException;
26 import java.util.Collections;
27 import java.util.List;
28 import java.util.concurrent.atomic.AtomicReference;
29
30 import org.apache.commons.logging.Log;
31 import org.apache.commons.logging.LogFactory;
32 import org.apache.hadoop.hbase.classification.InterfaceAudience;
33 import org.apache.hadoop.conf.Configuration;
34 import org.apache.hadoop.fs.FSDataInputStream;
35 import org.apache.hadoop.fs.FileSystem;
36 import org.apache.hadoop.fs.Path;
37 import org.apache.hadoop.hbase.wal.WAL.Reader;
38 import org.apache.hadoop.hbase.wal.WALProvider.Writer;
39 import org.apache.hadoop.hbase.util.CancelableProgressable;
40 import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
41 import org.apache.hadoop.hbase.util.LeaseNotRecoveredException;
42
43
44 import org.apache.hadoop.hbase.regionserver.wal.MetricsWAL;
45 import org.apache.hadoop.hbase.regionserver.wal.ProtobufLogReader;
46 import org.apache.hadoop.hbase.regionserver.wal.SequenceFileLogReader;
47 import org.apache.hadoop.hbase.regionserver.wal.WALActionsListener;
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67 @InterfaceAudience.Private
68 public class WALFactory {
69
70 private static final Log LOG = LogFactory.getLog(WALFactory.class);
71
72
73
74
75 static enum Providers {
76 defaultProvider(DefaultWALProvider.class),
77 filesystem(DefaultWALProvider.class),
78 multiwal(RegionGroupingProvider.class);
79
80 final Class<? extends WALProvider> clazz;
81
82 Providers(Class<? extends WALProvider> clazz) {
83 this.clazz = clazz;
84 }
85 }
86
87 public static final String WAL_PROVIDER = "hbase.wal.provider";
88 static final String DEFAULT_WAL_PROVIDER = Providers.defaultProvider.name();
89
90 static final String META_WAL_PROVIDER = "hbase.wal.meta_provider";
91 static final String DEFAULT_META_WAL_PROVIDER = Providers.defaultProvider.name();
92
93 final String factoryId;
94 final WALProvider provider;
95
96
97
98 final AtomicReference<WALProvider> metaProvider = new AtomicReference<WALProvider>();
99
100
101
102
103 private final Class<? extends DefaultWALProvider.Reader> logReaderClass;
104
105
106
107
108 private final int timeoutMillis;
109
110 private final Configuration conf;
111
112
113 private WALFactory(Configuration conf) {
114
115
116
117 timeoutMillis = conf.getInt("hbase.hlog.open.timeout", 300000);
118
119 logReaderClass = conf.getClass("hbase.regionserver.hlog.reader.impl", ProtobufLogReader.class,
120 DefaultWALProvider.Reader.class);
121 this.conf = conf;
122
123
124
125 provider = null;
126 factoryId = SINGLETON_ID;
127 }
128
129 Class<? extends WALProvider> getProviderClass(String key, String defaultValue) {
130 try {
131 return Providers.valueOf(conf.get(key, defaultValue)).clazz;
132 } catch (IllegalArgumentException exception) {
133
134
135
136 return conf.getClass(key, DefaultWALProvider.class, WALProvider.class);
137 }
138 }
139
140 WALProvider createProvider(Class<? extends WALProvider> clazz,
141 List<WALActionsListener> listeners, String providerId) throws IOException {
142 LOG.info("Instantiating WALProvider of type " + clazz);
143 try {
144 final WALProvider result = clazz.getDeclaredConstructor().newInstance();
145 result.init(this, conf, listeners, providerId);
146 return result;
147 } catch (Exception e) {
148 LOG.error("couldn't set up WALProvider, the configured class is " + clazz);
149 LOG.debug("Exception details for failure to load WALProvider.", e);
150 throw new IOException("couldn't set up WALProvider", e);
151 }
152 }
153
154
155
156
157
158 WALProvider getProvider(final String key, final String defaultValue,
159 final List<WALActionsListener> listeners, final String providerId) throws IOException {
160 Class<? extends WALProvider> clazz = getProviderClass(key, defaultValue);
161 return createProvider(clazz, listeners, providerId);
162 }
163
164
165
166
167
168
169
170
171 public WALFactory(final Configuration conf, final List<WALActionsListener> listeners,
172 final String factoryId) throws IOException {
173
174
175 timeoutMillis = conf.getInt("hbase.hlog.open.timeout", 300000);
176
177 logReaderClass = conf.getClass("hbase.regionserver.hlog.reader.impl", ProtobufLogReader.class,
178 DefaultWALProvider.Reader.class);
179 this.conf = conf;
180 this.factoryId = factoryId;
181
182 if (conf.getBoolean("hbase.regionserver.hlog.enabled", true)) {
183 provider = getProvider(WAL_PROVIDER, DEFAULT_WAL_PROVIDER, listeners, null);
184 } else {
185
186 LOG.warn("Running with WAL disabled.");
187 provider = new DisabledWALProvider();
188 provider.init(this, conf, null, factoryId);
189 }
190 }
191
192
193
194
195
196
197 public void close() throws IOException {
198 final WALProvider metaProvider = this.metaProvider.get();
199 if (null != metaProvider) {
200 metaProvider.close();
201 }
202
203
204 if (null != provider) {
205 provider.close();
206 }
207 }
208
209
210
211
212
213
214 public void shutdown() throws IOException {
215 IOException exception = null;
216 final WALProvider metaProvider = this.metaProvider.get();
217 if (null != metaProvider) {
218 try {
219 metaProvider.shutdown();
220 } catch(IOException ioe) {
221 exception = ioe;
222 }
223 }
224 provider.shutdown();
225 if (null != exception) {
226 throw exception;
227 }
228 }
229
230 public List<WAL> getWALs() throws IOException {
231 return provider.getWALs();
232 }
233
234
235
236
237
238 public WAL getWAL(final byte[] identifier, final byte[] namespace) throws IOException {
239 return provider.getWAL(identifier, namespace);
240 }
241
242
243
244
245 public WAL getMetaWAL(final byte[] identifier) throws IOException {
246 WALProvider metaProvider = this.metaProvider.get();
247 if (null == metaProvider) {
248 final WALProvider temp = getProvider(META_WAL_PROVIDER, DEFAULT_META_WAL_PROVIDER,
249 Collections.<WALActionsListener>singletonList(new MetricsWAL()),
250 DefaultWALProvider.META_WAL_PROVIDER_ID);
251 if (this.metaProvider.compareAndSet(null, temp)) {
252 metaProvider = temp;
253 } else {
254
255 temp.close();
256 metaProvider = this.metaProvider.get();
257 }
258 }
259 return metaProvider.getWAL(identifier, null);
260 }
261
262 public Reader createReader(final FileSystem fs, final Path path) throws IOException {
263 return createReader(fs, path, (CancelableProgressable)null);
264 }
265
266
267
268
269
270
271
272
273 public Reader createReader(final FileSystem fs, final Path path,
274 CancelableProgressable reporter) throws IOException {
275 return createReader(fs, path, reporter, true);
276 }
277
278 public Reader createReader(final FileSystem fs, final Path path,
279 CancelableProgressable reporter, boolean allowCustom)
280 throws IOException {
281 Class<? extends DefaultWALProvider.Reader> lrClass =
282 allowCustom ? logReaderClass : ProtobufLogReader.class;
283
284 try {
285
286
287
288 long startWaiting = EnvironmentEdgeManager.currentTime();
289 long openTimeout = timeoutMillis + startWaiting;
290 int nbAttempt = 0;
291 FSDataInputStream stream = null;
292 DefaultWALProvider.Reader reader = null;
293 while (true) {
294 try {
295 if (lrClass != ProtobufLogReader.class) {
296
297 reader = lrClass.getDeclaredConstructor().newInstance();
298 reader.init(fs, path, conf, null);
299 return reader;
300 } else {
301 stream = fs.open(path);
302
303
304
305
306 byte[] magic = new byte[ProtobufLogReader.PB_WAL_MAGIC.length];
307 boolean isPbWal = (stream.read(magic) == magic.length)
308 && Arrays.equals(magic, ProtobufLogReader.PB_WAL_MAGIC);
309 reader =
310 isPbWal ? new ProtobufLogReader() : new SequenceFileLogReader();
311 reader.init(fs, path, conf, stream);
312 return reader;
313 }
314 } catch (Exception e) {
315 if (stream != null) {
316 try {
317 stream.close();
318 } catch (IOException exception) {
319 LOG.warn("Could not close DefaultWALProvider.Reader" + exception.getMessage());
320 LOG.debug("exception details", exception);
321 }
322 }
323 if (reader != null) {
324 try {
325 reader.close();
326 } catch (IOException exception) {
327 LOG.warn("Could not close FSDataInputStream" + exception.getMessage());
328 LOG.debug("exception details", exception);
329 }
330 }
331 if (e instanceof IOException) {
332 String msg = e.getMessage();
333 if (msg != null && (msg.contains("Cannot obtain block length")
334 || msg.contains("Could not obtain the last block")
335 || msg.matches("Blocklist for [^ ]* has changed.*"))) {
336 if (++nbAttempt == 1) {
337 LOG.warn("Lease should have recovered. This is not expected. Will retry", e);
338 }
339 if (reporter != null && !reporter.progress()) {
340 throw new InterruptedIOException("Operation is cancelled");
341 }
342 if (nbAttempt > 2 && openTimeout < EnvironmentEdgeManager.currentTime()) {
343 LOG.error("Can't open after " + nbAttempt + " attempts and "
344 + (EnvironmentEdgeManager.currentTime() - startWaiting)
345 + "ms " + " for " + path);
346 } else {
347 try {
348 Thread.sleep(nbAttempt < 3 ? 500 : 1000);
349 continue;
350 } catch (InterruptedException ie) {
351 InterruptedIOException iioe = new InterruptedIOException();
352 iioe.initCause(ie);
353 throw iioe;
354 }
355 }
356 throw new LeaseNotRecoveredException(e);
357 } else {
358 throw e;
359 }
360 }
361
362
363 throw e;
364 }
365 }
366 } catch (IOException ie) {
367 throw ie;
368 } catch (Exception e) {
369 throw new IOException("Cannot get log reader", e);
370 }
371 }
372
373
374
375
376
377
378
379
380 public Writer createWALWriter(final FileSystem fs, final Path path) throws IOException {
381 return DefaultWALProvider.createWriter(conf, fs, path, false);
382 }
383
384
385
386
387
388 public Writer createRecoveredEditsWriter(final FileSystem fs, final Path path)
389 throws IOException {
390 return DefaultWALProvider.createWriter(conf, fs, path, true);
391 }
392
393
394
395
396
397 private static final AtomicReference<WALFactory> singleton = new AtomicReference<WALFactory>();
398 private static final String SINGLETON_ID = WALFactory.class.getName();
399
400
401 public static WALFactory getInstance(Configuration configuration) {
402 WALFactory factory = singleton.get();
403 if (null == factory) {
404 WALFactory temp = new WALFactory(configuration);
405 if (singleton.compareAndSet(null, temp)) {
406 factory = temp;
407 } else {
408
409 try {
410 temp.close();
411 } catch (IOException exception) {
412 LOG.debug("failed to close temporary singleton. ignoring.", exception);
413 }
414 factory = singleton.get();
415 }
416 }
417 return factory;
418 }
419
420
421
422
423
424
425 public static Reader createReader(final FileSystem fs, final Path path,
426 final Configuration configuration) throws IOException {
427 return getInstance(configuration).createReader(fs, path);
428 }
429
430
431
432
433
434
435 static Reader createReader(final FileSystem fs, final Path path,
436 final Configuration configuration, final CancelableProgressable reporter) throws IOException {
437 return getInstance(configuration).createReader(fs, path, reporter);
438 }
439
440
441
442
443
444
445
446 public static Reader createReaderIgnoreCustomClass(final FileSystem fs, final Path path,
447 final Configuration configuration) throws IOException {
448 return getInstance(configuration).createReader(fs, path, null, false);
449 }
450
451
452
453
454
455 static Writer createRecoveredEditsWriter(final FileSystem fs, final Path path,
456 final Configuration configuration)
457 throws IOException {
458 return DefaultWALProvider.createWriter(configuration, fs, path, true);
459 }
460
461
462
463
464
465 public static Writer createWALWriter(final FileSystem fs, final Path path,
466 final Configuration configuration)
467 throws IOException {
468 return DefaultWALProvider.createWriter(configuration, fs, path, false);
469 }
470
471 public final WALProvider getWALProvider() {
472 return this.provider;
473 }
474
475 public final WALProvider getMetaWALProvider() {
476 return this.metaProvider.get();
477 }
478 }