3232import org .apache .hadoop .hbase .Server ;
3333import org .apache .hadoop .hbase .regionserver .wal .FSHLog ;
3434import org .apache .hadoop .hbase .regionserver .wal .FailedLogCloseException ;
35+ import org .apache .hadoop .hbase .util .EnvironmentEdgeManager ;
3536import org .apache .hadoop .hbase .wal .WAL ;
3637import org .apache .hadoop .hbase .regionserver .wal .WALActionsListener ;
3738import org .apache .hadoop .hbase .util .Bytes ;
@@ -56,23 +57,27 @@ public class LogRoller extends HasThread {
5657 private static final Log LOG = LogFactory .getLog (LogRoller .class );
5758 private final ReentrantLock rollLock = new ReentrantLock ();
5859 private final AtomicBoolean rollLog = new AtomicBoolean (false );
59- private final ConcurrentHashMap <WAL , Boolean > walNeedsRoll =
60- new ConcurrentHashMap <WAL , Boolean >();
60+ private final ConcurrentHashMap <WAL , RollController > wals =
61+ new ConcurrentHashMap <WAL , RollController >();
6162 private final Server server ;
6263 protected final RegionServerServices services ;
63- private volatile long lastrolltime = System .currentTimeMillis ();
6464 // Period to roll log.
65- private final long rollperiod ;
65+ private final long rollPeriod ;
6666 private final int threadWakeFrequency ;
6767 // The interval to check low replication on hlog's pipeline
68- private long checkLowReplicationInterval ;
68+ private final long checkLowReplicationInterval ;
6969
7070 public void addWAL (final WAL wal ) {
71- if (null == walNeedsRoll .putIfAbsent (wal , Boolean . FALSE )) {
71+ if (null == wals .putIfAbsent (wal , new RollController ( wal ) )) {
7272 wal .registerWALActionsListener (new WALActionsListener .Base () {
7373 @ Override
7474 public void logRollRequested (WALActionsListener .RollRequestReason reason ) {
75- walNeedsRoll .put (wal , Boolean .TRUE );
75+ RollController controller = wals .get (wal );
76+ if (controller == null ) {
77+ wals .putIfAbsent (wal , new RollController (wal ));
78+ controller = wals .get (wal );
79+ }
80+ controller .requestRoll ();
7681 // TODO logs will contend with each other here, replace with e.g. DelayedQueue
7782 synchronized (rollLog ) {
7883 rollLog .set (true );
@@ -84,8 +89,8 @@ public void logRollRequested(WALActionsListener.RollRequestReason reason) {
8489 }
8590
8691 public void requestRollAll () {
87- for (WAL wal : walNeedsRoll . keySet ()) {
88- walNeedsRoll . put ( wal , Boolean . TRUE );
92+ for (RollController controller : wals . values ()) {
93+ controller . requestRoll ( );
8994 }
9095 synchronized (rollLog ) {
9196 rollLog .set (true );
@@ -98,7 +103,7 @@ public LogRoller(final Server server, final RegionServerServices services) {
98103 super ("LogRoller" );
99104 this .server = server ;
100105 this .services = services ;
101- this .rollperiod = this .server .getConfiguration ().
106+ this .rollPeriod = this .server .getConfiguration ().
102107 getLong ("hbase.regionserver.logroll.period" , 3600000 );
103108 this .threadWakeFrequency = this .server .getConfiguration ().
104109 getInt (HConstants .THREAD_WAKE_FREQUENCY , 10 * 1000 );
@@ -120,9 +125,9 @@ public void interrupt() {
120125 */
121126 void checkLowReplication (long now ) {
122127 try {
123- for (Entry <WAL , Boolean > entry : walNeedsRoll .entrySet ()) {
128+ for (Entry <WAL , RollController > entry : wals .entrySet ()) {
124129 WAL wal = entry .getKey ();
125- boolean neeRollAlready = entry .getValue ();
130+ boolean neeRollAlready = entry .getValue (). needsRoll ( now ) ;
126131 if (wal instanceof FSHLog && !neeRollAlready ) {
127132 FSHLog hlog = (FSHLog )wal ;
128133 if ((now - hlog .getLastTimeCheckLowReplication ())
@@ -139,11 +144,16 @@ void checkLowReplication(long now) {
139144 @ Override
140145 public void run () {
141146 while (!server .isStopped ()) {
142- long now = System . currentTimeMillis ();
147+ long now = EnvironmentEdgeManager . currentTime ();
143148 checkLowReplication (now );
144- boolean periodic = false ;
145149 if (!rollLog .get ()) {
146- periodic = (now - this .lastrolltime ) > this .rollperiod ;
150+ boolean periodic = false ;
151+ for (RollController controller : wals .values ()) {
152+ if (controller .needsPeriodicRoll (now )) {
153+ periodic = true ;
154+ break ;
155+ }
156+ }
147157 if (!periodic ) {
148158 synchronized (rollLog ) {
149159 try {
@@ -156,23 +166,24 @@ public void run() {
156166 }
157167 continue ;
158168 }
159- // Time for periodic roll
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" );
165169 }
166170 rollLock .lock (); // FindBugs UL_UNRELEASED_LOCK_EXCEPTION_PATH
167171 try {
168- this .lastrolltime = now ;
169- for (Entry <WAL , Boolean > entry : walNeedsRoll .entrySet ()) {
172+ for (Entry <WAL , RollController > entry : wals .entrySet ()) {
170173 final WAL wal = entry .getKey ();
174+ RollController controller = entry .getValue ();
175+ if (controller .isRollRequested ()) {
176+ // WAL roll requested, fall through
177+ LOG .debug ("WAL " + wal + " roll requested" );
178+ } else if (controller .needsPeriodicRoll (now )) {
179+ // Time for periodic roll, fall through
180+ LOG .debug ("WAL " + wal + " roll period " + this .rollPeriod + "ms elapsed" );
181+ } else {
182+ continue ;
183+ }
171184 // Force the roll if the logroll.period is elapsed or if a roll was requested.
172185 // The returned value is an array of actual region names.
173- final byte [][] regionsToFlush = wal .rollWriter (periodic ||
174- entry .getValue ().booleanValue ());
175- walNeedsRoll .put (wal , Boolean .FALSE );
186+ final byte [][] regionsToFlush = controller .rollWal (now );
176187 if (regionsToFlush != null ) {
177188 for (byte [] r : regionsToFlush ) scheduleFlush (r );
178189 }
@@ -229,11 +240,52 @@ private void scheduleFlush(final byte [] encodedRegionName) {
229240 */
230241 @ VisibleForTesting
231242 public boolean walRollFinished () {
232- for (boolean needRoll : walNeedsRoll .values ()) {
233- if (needRoll ) {
243+ long now = EnvironmentEdgeManager .currentTime ();
244+ for (RollController controller : wals .values ()) {
245+ if (controller .needsRoll (now )) {
234246 return false ;
235247 }
236248 }
237249 return true ;
238250 }
251+
252+
253+ /**
254+ * Independently control the roll of each wal. When use multiwal,
255+ * can avoid all wal roll together. see HBASE-24665 for detail
256+ */
257+ protected class RollController {
258+ private final WAL wal ;
259+ private final AtomicBoolean rollRequest ;
260+ private long lastRollTime ;
261+
262+ RollController (WAL wal ) {
263+ this .wal = wal ;
264+ this .rollRequest = new AtomicBoolean (false );
265+ this .lastRollTime = EnvironmentEdgeManager .currentTime ();
266+ }
267+
268+ public void requestRoll () {
269+ this .rollRequest .set (true );
270+ }
271+
272+ public byte [][] rollWal (long now ) throws IOException {
273+ this .lastRollTime = now ;
274+ byte [][] regionsToFlush = wal .rollWriter (true );
275+ this .rollRequest .set (false );
276+ return regionsToFlush ;
277+ }
278+
279+ public boolean isRollRequested () {
280+ return rollRequest .get ();
281+ }
282+
283+ public boolean needsPeriodicRoll (long now ) {
284+ return (now - this .lastRollTime ) > rollPeriod ;
285+ }
286+
287+ public boolean needsRoll (long now ) {
288+ return isRollRequested () || needsPeriodicRoll (now );
289+ }
290+ }
239291}
0 commit comments