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