1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.regionserver;
20
21 import java.io.IOException;
22 import java.util.Map.Entry;
23 import java.util.concurrent.ConcurrentHashMap;
24 import java.util.concurrent.atomic.AtomicBoolean;
25 import java.util.concurrent.locks.ReentrantLock;
26
27 import org.apache.commons.logging.Log;
28 import org.apache.commons.logging.LogFactory;
29 import org.apache.hadoop.hbase.classification.InterfaceAudience;
30 import org.apache.hadoop.hbase.HConstants;
31 import org.apache.hadoop.hbase.RemoteExceptionHandler;
32 import org.apache.hadoop.hbase.Server;
33 import org.apache.hadoop.hbase.regionserver.wal.FSHLog;
34 import org.apache.hadoop.hbase.regionserver.wal.FailedLogCloseException;
35 import org.apache.hadoop.hbase.wal.WAL;
36 import org.apache.hadoop.hbase.regionserver.wal.WALActionsListener;
37 import org.apache.hadoop.hbase.util.Bytes;
38 import org.apache.hadoop.hbase.util.HasThread;
39
40 import com.google.common.annotations.VisibleForTesting;
41
42
43
44
45
46
47
48
49
50
51 @InterfaceAudience.Private
52 @VisibleForTesting
53 @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="JLM_JSR166_UTILCONCURRENT_MONITORENTER",
54 justification="Use of an atomic type both as monitor and condition variable is intended")
55 public class LogRoller extends HasThread {
56 private static final Log LOG = LogFactory.getLog(LogRoller.class);
57 private final ReentrantLock rollLock = new ReentrantLock();
58 private final AtomicBoolean rollLog = new AtomicBoolean(false);
59 private final ConcurrentHashMap<WAL, Boolean> walNeedsRoll =
60 new ConcurrentHashMap<WAL, Boolean>();
61 private final Server server;
62 protected final RegionServerServices services;
63 private volatile long lastrolltime = System.currentTimeMillis();
64
65 private final long rollperiod;
66 private final int threadWakeFrequency;
67
68 private long checkLowReplicationInterval;
69
70 public void addWAL(final WAL wal) {
71 if (null == walNeedsRoll.putIfAbsent(wal, Boolean.FALSE)) {
72 wal.registerWALActionsListener(new WALActionsListener.Base() {
73 @Override
74 public void logRollRequested(boolean lowReplicas) {
75 walNeedsRoll.put(wal, Boolean.TRUE);
76
77 synchronized(rollLog) {
78 rollLog.set(true);
79 rollLog.notifyAll();
80 }
81 }
82 });
83 }
84 }
85
86 public void requestRollAll() {
87 for (WAL wal : walNeedsRoll.keySet()) {
88 walNeedsRoll.put(wal, Boolean.TRUE);
89 }
90 synchronized(rollLog) {
91 rollLog.set(true);
92 rollLog.notifyAll();
93 }
94 }
95
96
97 public LogRoller(final Server server, final RegionServerServices services) {
98 super("LogRoller");
99 this.server = server;
100 this.services = services;
101 this.rollperiod = this.server.getConfiguration().
102 getLong("hbase.regionserver.logroll.period", 3600000);
103 this.threadWakeFrequency = this.server.getConfiguration().
104 getInt(HConstants.THREAD_WAKE_FREQUENCY, 10 * 1000);
105 this.checkLowReplicationInterval = this.server.getConfiguration().getLong(
106 "hbase.regionserver.hlog.check.lowreplication.interval", 30 * 1000);
107 }
108
109 @Override
110 public void interrupt() {
111
112 synchronized (rollLog) {
113 this.rollLog.notify();
114 }
115 super.interrupt();
116 }
117
118
119
120
121 void checkLowReplication(long now) {
122 try {
123 for (Entry<WAL, Boolean> entry : walNeedsRoll.entrySet()) {
124 WAL wal = entry.getKey();
125 boolean neeRollAlready = entry.getValue();
126 if(wal instanceof FSHLog && !neeRollAlready) {
127 FSHLog hlog = (FSHLog)wal;
128 if ((now - hlog.getLastTimeCheckLowReplication())
129 > this.checkLowReplicationInterval) {
130 hlog.checkLogRoll();
131 }
132 }
133 }
134 } catch (Throwable e) {
135 LOG.warn("Failed checking low replication", e);
136 }
137 }
138
139 @Override
140 public void run() {
141 while (!server.isStopped()) {
142 long now = System.currentTimeMillis();
143 checkLowReplication(now);
144 boolean periodic = false;
145 if (!rollLog.get()) {
146 periodic = (now - this.lastrolltime) > this.rollperiod;
147 if (!periodic) {
148 synchronized (rollLog) {
149 try {
150 if (!rollLog.get()) {
151 rollLog.wait(this.threadWakeFrequency);
152 }
153 } catch (InterruptedException e) {
154
155 }
156 }
157 continue;
158 }
159
160 if (LOG.isDebugEnabled()) {
161 LOG.debug("Wal roll period " + this.rollperiod + "ms elapsed");
162 }
163 } else if (LOG.isDebugEnabled()) {
164 LOG.debug("WAL roll requested");
165 }
166 rollLock.lock();
167 try {
168 this.lastrolltime = now;
169 for (Entry<WAL, Boolean> entry : walNeedsRoll.entrySet()) {
170 final WAL wal = entry.getKey();
171
172
173 final byte [][] regionsToFlush = wal.rollWriter(periodic ||
174 entry.getValue().booleanValue());
175 walNeedsRoll.put(wal, Boolean.FALSE);
176 if (regionsToFlush != null) {
177 for (byte [] r: regionsToFlush) scheduleFlush(r);
178 }
179 }
180 } catch (FailedLogCloseException e) {
181 server.abort("Failed log close in log roller", e);
182 } catch (java.net.ConnectException e) {
183 server.abort("Failed log close in log roller", e);
184 } catch (IOException ex) {
185 LOG.fatal("Aborting", ex);
186
187 server.abort("IOE in log roller",
188 RemoteExceptionHandler.checkIOException(ex));
189 } catch (Exception ex) {
190 final String msg = "Failed rolling WAL; aborting to recover edits!";
191 LOG.error(msg, ex);
192 server.abort(msg, ex);
193 } finally {
194 try {
195 rollLog.set(false);
196 } finally {
197 rollLock.unlock();
198 }
199 }
200 }
201 LOG.info("LogRoller exiting.");
202 }
203
204
205
206
207 private void scheduleFlush(final byte [] encodedRegionName) {
208 boolean scheduled = false;
209 Region r = this.services.getFromOnlineRegions(Bytes.toString(encodedRegionName));
210 FlushRequester requester = null;
211 if (r != null) {
212 requester = this.services.getFlushRequester();
213 if (requester != null) {
214
215 requester.requestFlush(r, true);
216 scheduled = true;
217 }
218 }
219 if (!scheduled) {
220 LOG.warn("Failed to schedule flush of " +
221 Bytes.toString(encodedRegionName) + ", region=" + r + ", requester=" +
222 requester);
223 }
224 }
225
226
227
228
229
230 @VisibleForTesting
231 public boolean walRollFinished() {
232 for (boolean needRoll : walNeedsRoll.values()) {
233 if (needRoll) {
234 return false;
235 }
236 }
237 return true;
238 }
239 }