1 /**
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19
20 package org.apache.hadoop.hbase.regionserver.wal;
21
22 import java.io.DataInput;
23 import java.io.DataOutput;
24 import java.io.IOException;
25 import java.util.UUID;
26 import java.util.regex.Pattern;
27
28 import org.apache.commons.logging.Log;
29 import org.apache.commons.logging.LogFactory;
30 import org.apache.hadoop.classification.InterfaceAudience;
31 import org.apache.hadoop.conf.Configuration;
32 import org.apache.hadoop.fs.FSDataInputStream;
33 import org.apache.hadoop.fs.FileSystem;
34 import org.apache.hadoop.fs.Path;
35 import org.apache.hadoop.hbase.TableName;
36 import org.apache.hadoop.hbase.HRegionInfo;
37 import org.apache.hadoop.hbase.HTableDescriptor;
38 import org.apache.hadoop.hbase.protobuf.generated.WALProtos.WALTrailer;
39 import org.apache.hadoop.io.Writable;
40
41
42 @InterfaceAudience.Private
43 public interface HLog {
44 Log LOG = LogFactory.getLog(HLog.class);
45
46 /** File Extension used while splitting an HLog into regions (HBASE-2312) */
47 String SPLITTING_EXT = "-splitting";
48 boolean SPLIT_SKIP_ERRORS_DEFAULT = false;
49 /** The META region's HLog filename extension */
50 String META_HLOG_FILE_EXTN = ".meta";
51
52 /**
53 * Configuration name of HLog Trailer's warning size. If a waltrailer's size is greater than the
54 * configured size, a warning is logged. This is used with Protobuf reader/writer.
55 */
56 String WAL_TRAILER_WARN_SIZE =
57 "hbase.regionserver.waltrailer.warn.size";
58 int DEFAULT_WAL_TRAILER_WARN_SIZE = 1024*1024; // 1MB
59
60 Pattern EDITFILES_NAME_PATTERN = Pattern.compile("-?[0-9]+");
61 String RECOVERED_LOG_TMPFILE_SUFFIX = ".temp";
62
63 interface Reader {
64
65 /**
66 * @param fs File system.
67 * @param path Path.
68 * @param c Config.
69 * @param s Input stream that may have been pre-opened by the caller; may be null.
70 */
71 void init(FileSystem fs, Path path, Configuration c, FSDataInputStream s) throws IOException;
72
73 void close() throws IOException;
74
75 Entry next() throws IOException;
76
77 Entry next(Entry reuse) throws IOException;
78
79 void seek(long pos) throws IOException;
80
81 long getPosition() throws IOException;
82 void reset() throws IOException;
83
84 /**
85 * @return the WALTrailer of the current HLog. It may be null in case of legacy or corrupt WAL
86 * files.
87 */
88 WALTrailer getWALTrailer();
89 }
90
91 interface Writer {
92 void init(FileSystem fs, Path path, Configuration c) throws IOException;
93
94 void close() throws IOException;
95
96 void sync() throws IOException;
97
98 void append(Entry entry) throws IOException;
99
100 long getLength() throws IOException;
101
102 /**
103 * Sets HLog's WALTrailer. This trailer is appended at the end of WAL on closing.
104 * @param walTrailer trailer to append to WAL.
105 */
106 void setWALTrailer(WALTrailer walTrailer);
107 }
108
109 /**
110 * Utility class that lets us keep track of the edit with it's key Only used
111 * when splitting logs
112 */
113 class Entry implements Writable {
114 private WALEdit edit;
115 private HLogKey key;
116
117 public Entry() {
118 edit = new WALEdit();
119 key = new HLogKey();
120 }
121
122 /**
123 * Constructor for both params
124 *
125 * @param edit
126 * log's edit
127 * @param key
128 * log's key
129 */
130 public Entry(HLogKey key, WALEdit edit) {
131 super();
132 this.key = key;
133 this.edit = edit;
134 }
135
136 /**
137 * Gets the edit
138 *
139 * @return edit
140 */
141 public WALEdit getEdit() {
142 return edit;
143 }
144
145 /**
146 * Gets the key
147 *
148 * @return key
149 */
150 public HLogKey getKey() {
151 return key;
152 }
153
154 /**
155 * Set compression context for this entry.
156 *
157 * @param compressionContext
158 * Compression context
159 */
160 public void setCompressionContext(CompressionContext compressionContext) {
161 edit.setCompressionContext(compressionContext);
162 key.setCompressionContext(compressionContext);
163 }
164
165 @Override
166 public String toString() {
167 return this.key + "=" + this.edit;
168 }
169
170 @Override
171 public void write(DataOutput dataOutput) throws IOException {
172 this.key.write(dataOutput);
173 this.edit.write(dataOutput);
174 }
175
176 @Override
177 public void readFields(DataInput dataInput) throws IOException {
178 this.key.readFields(dataInput);
179 this.edit.readFields(dataInput);
180 }
181 }
182
183 /**
184 * registers WALActionsListener
185 *
186 * @param listener
187 */
188 void registerWALActionsListener(final WALActionsListener listener);
189
190 /**
191 * unregisters WALActionsListener
192 *
193 * @param listener
194 */
195 boolean unregisterWALActionsListener(final WALActionsListener listener);
196
197 /**
198 * @return Current state of the monotonically increasing file id.
199 */
200 long getFilenum();
201
202 /**
203 * Called by HRegionServer when it opens a new region to ensure that log
204 * sequence numbers are always greater than the latest sequence number of the
205 * region being brought on-line.
206 *
207 * @param newvalue
208 * We'll set log edit/sequence number to this value if it is greater
209 * than the current value.
210 */
211 void setSequenceNumber(final long newvalue);
212
213 /**
214 * @return log sequence number
215 */
216 long getSequenceNumber();
217
218 /**
219 * Roll the log writer. That is, start writing log messages to a new file.
220 *
221 * <p>
222 * The implementation is synchronized in order to make sure there's one rollWriter
223 * running at any given time.
224 *
225 * @return If lots of logs, flush the returned regions so next time through we
226 * can clean logs. Returns null if nothing to flush. Names are actual
227 * region names as returned by {@link HRegionInfo#getEncodedName()}
228 * @throws org.apache.hadoop.hbase.regionserver.wal.FailedLogCloseException
229 * @throws IOException
230 */
231 byte[][] rollWriter() throws FailedLogCloseException, IOException;
232
233 /**
234 * Roll the log writer. That is, start writing log messages to a new file.
235 *
236 * <p>
237 * The implementation is synchronized in order to make sure there's one rollWriter
238 * running at any given time.
239 *
240 * @param force
241 * If true, force creation of a new writer even if no entries have
242 * been written to the current writer
243 * @return If lots of logs, flush the returned regions so next time through we
244 * can clean logs. Returns null if nothing to flush. Names are actual
245 * region names as returned by {@link HRegionInfo#getEncodedName()}
246 * @throws org.apache.hadoop.hbase.regionserver.wal.FailedLogCloseException
247 * @throws IOException
248 */
249 byte[][] rollWriter(boolean force) throws FailedLogCloseException,
250 IOException;
251
252 /**
253 * Shut down the log.
254 *
255 * @throws IOException
256 */
257 void close() throws IOException;
258
259 /**
260 * Shut down the log and delete the log directory
261 *
262 * @throws IOException
263 */
264 void closeAndDelete() throws IOException;
265
266 /**
267 * Same as {@link #appendNoSync(HRegionInfo, TableName, WALEdit, UUID, long, HTableDescriptor)},
268 * except it causes a sync on the log
269 */
270 public void append(HRegionInfo info, TableName tableName, WALEdit edits,
271 final long now, HTableDescriptor htd) throws IOException;
272
273 /**
274 * Append a set of edits to the log. Log edits are keyed by (encoded)
275 * regionName, rowname, and log-sequence-id. The HLog is flushed after this
276 * transaction is written to the log.
277 * @param info
278 * @param tableName
279 * @param edits
280 * @param now
281 * @param htd
282 * @param isInMemstore Whether the record is in memstore. False for system records.
283 */
284 public void append(HRegionInfo info, TableName tableName, WALEdit edits,
285 final long now, HTableDescriptor htd, boolean isInMemstore) throws IOException;
286
287 /**
288 * Append a set of edits to the log. Log edits are keyed by (encoded)
289 * regionName, rowname, and log-sequence-id. The HLog is not flushed after
290 * this transaction is written to the log.
291 *
292 * @param info
293 * @param tableName
294 * @param edits
295 * @param clusterId
296 * The originating clusterId for this edit (for replication)
297 * @param now
298 * @param htd
299 * @return txid of this transaction
300 * @throws IOException
301 */
302 public long appendNoSync(HRegionInfo info, TableName tableName, WALEdit edits,
303 UUID clusterId, final long now, HTableDescriptor htd) throws IOException;
304
305 void hsync() throws IOException;
306
307 void hflush() throws IOException;
308
309 void sync() throws IOException;
310
311 void sync(long txid) throws IOException;
312
313 /**
314 * Obtain a log sequence number.
315 */
316 long obtainSeqNum();
317
318 /**
319 * WAL keeps track of the sequence numbers that were not yet flushed from memstores
320 * in order to be able to do cleanup. This method tells WAL that some region is about
321 * to flush memstore.
322 *
323 * We stash the oldest seqNum for the region, and let the the next edit inserted in this
324 * region be recorded in {@link #append(HRegionInfo, TableName, WALEdit, long, HTableDescriptor)}
325 * as new oldest seqnum. In case of flush being aborted, we put the stashed value back;
326 * in case of flush succeeding, the seqNum of that first edit after start becomes the
327 * valid oldest seqNum for this region.
328 *
329 * @return current seqNum, to pass on to flushers (who will put it into the metadata of
330 * the resulting file as an upper-bound seqNum for that file), or NULL if flush
331 * should not be started.
332 */
333 Long startCacheFlush(final byte[] encodedRegionName);
334
335 /**
336 * Complete the cache flush.
337 * @param encodedRegionName Encoded region name.
338 */
339 void completeCacheFlush(final byte[] encodedRegionName);
340
341 /**
342 * Abort a cache flush. Call if the flush fails. Note that the only recovery
343 * for an aborted flush currently is a restart of the regionserver so the
344 * snapshot content dropped by the failure gets restored to the memstore.v
345 * @param encodedRegionName Encoded region name.
346 */
347 void abortCacheFlush(byte[] encodedRegionName);
348
349 /**
350 * @return Coprocessor host.
351 */
352 WALCoprocessorHost getCoprocessorHost();
353
354 /**
355 * Get LowReplication-Roller status
356 *
357 * @return lowReplicationRollEnabled
358 */
359 boolean isLowReplicationRollEnabled();
360
361 /** Gets the earliest sequence number in the memstore for this particular region.
362 * This can serve as best-effort "recent" WAL number for this region.
363 * @param encodedRegionName The region to get the number for.
364 * @return The number if present, HConstants.NO_SEQNUM if absent.
365 */
366 long getEarliestMemstoreSeqNum(byte[] encodedRegionName);
367 }