001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.wal; 019 020import java.io.Closeable; 021import java.io.IOException; 022import org.apache.hadoop.hbase.wal.WAL.Entry; 023import org.apache.yetus.audience.InterfaceAudience; 024 025/** 026 * A WAL reader which is designed for be able to tailing the WAL file which is currently being 027 * written. It adds support 028 */ 029@InterfaceAudience.Private 030public interface WALTailingReader extends Closeable { 031 032 enum State { 033 /** This means we read an Entry without any error */ 034 NORMAL, 035 /** 036 * This means the WAL file has a trailer and we have reached it, which means we have finished 037 * reading this file normally 038 */ 039 EOF_WITH_TRAILER, 040 /** 041 * This means we meet an error so the upper layer need to reset to read again 042 */ 043 ERROR_AND_RESET, 044 /** 045 * Mostly the same with the above {@link #ERROR_AND_RESET}, the difference is that here we also 046 * mess up the compression dictionary when reading data, so the upper layer should also clear 047 * the compression context when reseting, which means when calling resetTo method, we need to 048 * skip to the position instead of just seek to, which will impact performance. 049 */ 050 ERROR_AND_RESET_COMPRESSION, 051 /** 052 * This means we reach the EOF and the upper layer need to reset to see if there is more data. 053 * Notice that this does not mean that there is necessarily more data, the upper layer should 054 * determine whether they need to reset and read again. 055 */ 056 EOF_AND_RESET, 057 /** 058 * Mostly the same with the above {@link #EOF_AND_RESET}, the difference is that here we also 059 * mess up the compression dictionary when reading data, so the upper layer should also clear 060 * the compression context when reseting, which means when calling resetTo method, we need to 061 * skip to the position instead of just seek to, which will impact performance. The 062 * implementation should try its best to not fall into this situation. 063 */ 064 EOF_AND_RESET_COMPRESSION; 065 066 /** 067 * A dummy result for returning, as except {@link NORMAL}, for other state we do not need to 068 * provide fields other than state in the returned {@link Result}. 069 */ 070 private Result result = new Result(this, null, -1); 071 072 public Result getResult() { 073 return result; 074 } 075 076 public boolean resetCompression() { 077 return this == ERROR_AND_RESET_COMPRESSION || this == EOF_AND_RESET_COMPRESSION; 078 } 079 080 public boolean eof() { 081 return this == EOF_AND_RESET || this == EOF_AND_RESET_COMPRESSION || this == EOF_WITH_TRAILER; 082 } 083 } 084 085 final class Result { 086 087 private final State state; 088 private final Entry entry; 089 private final long entryEndPos; 090 091 public Result(State state, Entry entry, long entryEndPos) { 092 this.state = state; 093 this.entry = entry; 094 this.entryEndPos = entryEndPos; 095 } 096 097 public State getState() { 098 return state; 099 } 100 101 public Entry getEntry() { 102 return entry; 103 } 104 105 public long getEntryEndPos() { 106 return entryEndPos; 107 } 108 } 109 110 /** 111 * Read the next entry and make sure the position after reading does not go beyond the given 112 * {@code limit}. 113 * <p/> 114 * Notice that we will not throw any checked exception out, all the states are represented by the 115 * return value. Of course we will log the exceptions out. The reason why we do this is that, for 116 * tailing a WAL file which is currently being written, we will hit EOFException many times, so it 117 * should not be considered as an 'exception' and also, creating an Exception is a bit expensive. 118 * @param limit the position limit. See HBASE-14004 for more details about why we need this 119 * limitation. -1 means no limit. 120 */ 121 Result next(long limit); 122 123 /** 124 * Get the current reading position. 125 */ 126 long getPosition() throws IOException; 127 128 /** 129 * Reopen the reader to see if there is new data arrives, and also seek(or skip) to the given 130 * position. 131 * <p/> 132 * If you want to read from the beginning instead of a given position, please pass -1 as 133 * {@code position}, then the reader will locate to the first entry. Notice that, since we have a 134 * magic header and a pb header, the first WAL entry is not located at position 0, so passing 0 135 * will cause trouble. 136 * @param position the position we want to start reading from after resetting, or -1 if 137 * you want to start reading from the beginning. 138 * @param resetCompression whether we also need to clear the compression context. If {@code true}, 139 * we will use skip instead of seek after resetting. 140 */ 141 void resetTo(long position, boolean resetCompression) throws IOException; 142 143 /** 144 * Override to remove the 'throws IOException' as we are just a reader. 145 */ 146 @Override 147 void close(); 148}