1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.wal;
20
21 import java.io.IOException;
22 import java.util.ArrayList;
23 import java.util.Collections;
24 import java.util.List;
25 import java.util.concurrent.atomic.AtomicBoolean;
26 import java.util.regex.Pattern;
27
28 import com.google.common.annotations.VisibleForTesting;
29 import org.apache.commons.logging.Log;
30 import org.apache.commons.logging.LogFactory;
31 import org.apache.hadoop.hbase.classification.InterfaceAudience;
32 import org.apache.hadoop.hbase.classification.InterfaceStability;
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.HConstants;
38 import org.apache.hadoop.hbase.ServerName;
39 import org.apache.hadoop.hbase.util.FSUtils;
40
41
42 import org.apache.hadoop.hbase.regionserver.wal.FSHLog;
43 import org.apache.hadoop.hbase.regionserver.wal.ProtobufLogWriter;
44 import org.apache.hadoop.hbase.regionserver.wal.WALActionsListener;
45
46
47
48
49
50
51
52
53
54
55
56
57 @InterfaceAudience.Private
58 @InterfaceStability.Evolving
59 public class DefaultWALProvider implements WALProvider {
60 private static final Log LOG = LogFactory.getLog(DefaultWALProvider.class);
61
62
63 public interface Reader extends WAL.Reader {
64
65
66
67
68
69
70 void init(FileSystem fs, Path path, Configuration c, FSDataInputStream s) throws IOException;
71 }
72
73
74 public interface Writer extends WALProvider.Writer {
75 void init(FileSystem fs, Path path, Configuration c, boolean overwritable) throws IOException;
76 }
77
78 protected volatile FSHLog log = null;
79 private WALFactory factory = null;
80 private Configuration conf = null;
81 private List<WALActionsListener> listeners = null;
82 private String providerId = null;
83 private AtomicBoolean initialized = new AtomicBoolean(false);
84
85 private String logPrefix = null;
86
87
88
89
90 private final Object walCreateLock = new Object();
91
92
93
94
95
96
97
98
99 @Override
100 public void init(final WALFactory factory, final Configuration conf,
101 final List<WALActionsListener> listeners, String providerId) throws IOException {
102 if (!initialized.compareAndSet(false, true)) {
103 throw new IllegalStateException("WALProvider.init should only be called once.");
104 }
105 this.factory = factory;
106 this.conf = conf;
107 this.listeners = listeners;
108 this.providerId = providerId;
109
110 StringBuilder sb = new StringBuilder().append(factory.factoryId);
111 if (providerId != null) {
112 if (providerId.startsWith(WAL_FILE_NAME_DELIMITER)) {
113 sb.append(providerId);
114 } else {
115 sb.append(WAL_FILE_NAME_DELIMITER).append(providerId);
116 }
117 }
118 logPrefix = sb.toString();
119 }
120
121 @Override
122 public List<WAL> getWALs() throws IOException {
123 if (log == null) {
124 return Collections.emptyList();
125 }
126 List<WAL> wals = new ArrayList<WAL>();
127 wals.add(log);
128 return wals;
129 }
130
131 @Override
132 public WAL getWAL(final byte[] identifier, byte[] namespace) throws IOException {
133 if (log == null) {
134
135
136 synchronized (walCreateLock) {
137 if (log == null) {
138 log = new FSHLog(FSUtils.getWALFileSystem(conf), FSUtils.getWALRootDir(conf),
139 getWALDirectoryName(factory.factoryId), HConstants.HREGION_OLDLOGDIR_NAME, conf,
140 listeners, true, logPrefix,
141 META_WAL_PROVIDER_ID.equals(providerId) ? META_WAL_PROVIDER_ID : null);
142 }
143 }
144 }
145 return log;
146 }
147
148 @Override
149 public void close() throws IOException {
150 if (log != null) log.close();
151 }
152
153 @Override
154 public void shutdown() throws IOException {
155 if (log != null) log.shutdown();
156 }
157
158
159 public static final String WAL_FILE_NAME_DELIMITER = ".";
160
161 @VisibleForTesting
162 public static final String META_WAL_PROVIDER_ID = ".meta";
163 static final String DEFAULT_PROVIDER_ID = "default";
164
165
166
167 public static final String SPLITTING_EXT = "-splitting";
168
169
170
171
172
173
174 @Override
175 public long getNumLogFiles() {
176 return log == null ? 0 : this.log.getNumLogFiles();
177 }
178
179
180
181
182
183
184 @Override
185 public long getLogFileSize() {
186 return log == null ? 0 : this.log.getLogFileSize();
187 }
188
189
190
191
192 @VisibleForTesting
193 public static int getNumRolledLogFiles(WAL wal) {
194 return ((FSHLog)wal).getNumRolledLogFiles();
195 }
196
197
198
199
200 @VisibleForTesting
201 public static Path getCurrentFileName(final WAL wal) {
202 return ((FSHLog)wal).getCurrentFileName();
203 }
204
205
206
207
208 @VisibleForTesting
209 static void requestLogRoll(final WAL wal) {
210 ((FSHLog)wal).requestLogRoll();
211 }
212
213
214
215
216
217
218
219
220 @VisibleForTesting
221 public static long extractFileNumFromWAL(final WAL wal) {
222 final Path walName = ((FSHLog)wal).getCurrentFileName();
223 if (walName == null) {
224 throw new IllegalArgumentException("The WAL path couldn't be null");
225 }
226 final String[] walPathStrs = walName.toString().split("\\" + WAL_FILE_NAME_DELIMITER);
227 return Long.parseLong(walPathStrs[walPathStrs.length - (isMetaFile(walName) ? 2:1)]);
228 }
229
230
231
232
233
234 private static final Pattern pattern = Pattern.compile(".*\\.\\d*("+META_WAL_PROVIDER_ID+")*");
235
236
237
238
239
240
241
242
243
244
245
246 public static boolean validateWALFilename(String filename) {
247 return pattern.matcher(filename).matches();
248 }
249
250
251
252
253
254
255
256
257
258
259
260 public static String getWALDirectoryName(final String serverName) {
261 StringBuilder dirName = new StringBuilder(HConstants.HREGION_LOGDIR_NAME);
262 dirName.append("/");
263 dirName.append(serverName);
264 return dirName.toString();
265 }
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283 public static ServerName getServerNameFromWALDirectoryName(Configuration conf, String path)
284 throws IOException {
285 if (path == null
286 || path.length() <= HConstants.HREGION_LOGDIR_NAME.length()) {
287 return null;
288 }
289
290 if (conf == null) {
291 throw new IllegalArgumentException("parameter conf must be set");
292 }
293
294 final String walDir = FSUtils.getWALRootDir(conf).toString();
295
296 final StringBuilder startPathSB = new StringBuilder(walDir);
297 if (!walDir.endsWith("/"))
298 startPathSB.append('/');
299 startPathSB.append(HConstants.HREGION_LOGDIR_NAME);
300 if (!HConstants.HREGION_LOGDIR_NAME.endsWith("/"))
301 startPathSB.append('/');
302 final String startPath = startPathSB.toString();
303
304 String fullPath;
305 try {
306 fullPath = FileSystem.get(conf).makeQualified(new Path(path)).toString();
307 } catch (IllegalArgumentException e) {
308 LOG.info("Call to makeQualified failed on " + path + " " + e.getMessage());
309 return null;
310 }
311
312 if (!fullPath.startsWith(startPath)) {
313 return null;
314 }
315
316 final String serverNameAndFile = fullPath.substring(startPath.length());
317
318 if (serverNameAndFile.indexOf('/') < "a,0,0".length()) {
319
320 return null;
321 }
322
323 Path p = new Path(path);
324 return getServerNameFromWALDirectoryName(p);
325 }
326
327
328
329
330
331
332
333
334
335
336
337 public static ServerName getServerNameFromWALDirectoryName(Path logFile) {
338 String logDirName = logFile.getParent().getName();
339
340 if (logDirName.equals(HConstants.HREGION_LOGDIR_NAME)) {
341 logDirName = logFile.getName();
342 }
343 ServerName serverName = null;
344 if (logDirName.endsWith(SPLITTING_EXT)) {
345 logDirName = logDirName.substring(0, logDirName.length() - SPLITTING_EXT.length());
346 }
347 try {
348 serverName = ServerName.parseServerName(logDirName);
349 } catch (IllegalArgumentException ex) {
350 serverName = null;
351 LOG.warn("Cannot parse a server name from path=" + logFile + "; " + ex.getMessage());
352 }
353 if (serverName != null && serverName.getStartcode() < 0) {
354 LOG.warn("Invalid log file path=" + logFile);
355 serverName = null;
356 }
357 return serverName;
358 }
359
360 public static boolean isMetaFile(Path p) {
361 return isMetaFile(p.getName());
362 }
363
364 public static boolean isMetaFile(String p) {
365 if (p != null && p.endsWith(META_WAL_PROVIDER_ID)) {
366 return true;
367 }
368 return false;
369 }
370
371
372
373
374 public static Writer createWriter(final Configuration conf, final FileSystem fs, final Path path,
375 final boolean overwritable)
376 throws IOException {
377
378 Class<? extends Writer> logWriterClass = conf.getClass("hbase.regionserver.hlog.writer.impl",
379 ProtobufLogWriter.class, Writer.class);
380 Writer writer = null;
381 try {
382 writer = logWriterClass.getDeclaredConstructor().newInstance();
383 FileSystem rootFs = FileSystem.get(path.toUri(), conf);
384 writer.init(rootFs, path, conf, overwritable);
385 return writer;
386 } catch (Exception e) {
387 LOG.debug("Error instantiating log writer.", e);
388 if (writer != null) {
389 try{
390 writer.close();
391 } catch(IOException ee){
392 LOG.error("cannot close log writer", ee);
393 }
394 }
395 throw new IOException("cannot get log writer", e);
396 }
397 }
398
399
400
401
402
403
404
405 public static String getWALPrefixFromWALName(String name) {
406 int endIndex = name.replaceAll(META_WAL_PROVIDER_ID, "").lastIndexOf(".");
407 return name.substring(0, endIndex);
408 }
409
410 }