Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
core-edge: Batching inbound message queue for RAFT.
The RAFT message processing is now running on a dedicated thread distinct from the Netty networking thread. They are connected by a queue and new entry requests are batched together before being processed by the leader. This leads to batching when appending to the RAFT log and when sending new entries.
- Loading branch information
1 parent
50f03cb
commit fbd6105
Showing
20 changed files
with
634 additions
and
36 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
123 changes: 123 additions & 0 deletions
123
enterprise/core-edge/src/main/java/org/neo4j/coreedge/raft/BatchingMessageHandler.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
/* | ||
* Copyright (c) 2002-2016 "Neo Technology," | ||
* Network Engine for Objects in Lund AB [http://neotechnology.com] | ||
* | ||
* This file is part of Neo4j. | ||
* | ||
* Neo4j is free software: you can redistribute it and/or modify | ||
* it under the terms of the GNU Affero General Public License as | ||
* published by the Free Software Foundation, either version 3 of the | ||
* License, or (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU Affero General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU Affero General Public License | ||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
package org.neo4j.coreedge.raft; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.concurrent.ArrayBlockingQueue; | ||
import java.util.concurrent.BlockingQueue; | ||
|
||
import org.neo4j.coreedge.raft.RaftMessages.RaftMessage; | ||
import org.neo4j.coreedge.raft.net.Inbound.MessageHandler; | ||
import org.neo4j.logging.Log; | ||
import org.neo4j.logging.LogProvider; | ||
|
||
import static java.util.concurrent.TimeUnit.SECONDS; | ||
|
||
public class BatchingMessageHandler<MEMBER> implements Runnable, MessageHandler<RaftMessage<MEMBER>> | ||
{ | ||
private final Log log; | ||
private final MessageHandler<RaftMessage<MEMBER>> innerHandler; | ||
|
||
private final BlockingQueue<RaftMessage<MEMBER>> messageQueue; | ||
private final int maxBatch; | ||
private final List<RaftMessage<MEMBER>> batch; | ||
|
||
public BatchingMessageHandler( MessageHandler<RaftMessage<MEMBER>> innerHandler, LogProvider logProvider, int queueSize, int maxBatch ) | ||
{ | ||
this.innerHandler = innerHandler; | ||
this.log = logProvider.getLog( getClass() ); | ||
this.maxBatch = maxBatch; | ||
|
||
this.batch = new ArrayList<>( maxBatch ); | ||
this.messageQueue = new ArrayBlockingQueue<>( queueSize ); | ||
} | ||
|
||
@Override | ||
public void handle( RaftMessage<MEMBER> message ) | ||
{ | ||
try | ||
{ | ||
messageQueue.put( message ); | ||
} | ||
catch ( InterruptedException e ) | ||
{ | ||
log.warn( "Not expecting to be interrupted.", e ); | ||
} | ||
} | ||
|
||
@Override | ||
public void run() | ||
{ | ||
RaftMessage<MEMBER> message = null; | ||
try | ||
{ | ||
message = messageQueue.poll( 1, SECONDS ); | ||
} | ||
catch ( InterruptedException e ) | ||
{ | ||
log.warn( "Not expecting to be interrupted.", e ); | ||
} | ||
|
||
if ( message != null ) | ||
{ | ||
if ( messageQueue.isEmpty() ) | ||
{ | ||
innerHandler.handle( message ); | ||
} | ||
else | ||
{ | ||
batch.clear(); | ||
batch.add( message ); | ||
messageQueue.drainTo( batch, maxBatch - 1 ); | ||
|
||
collateAndHandleBatch( batch ); | ||
} | ||
} | ||
} | ||
|
||
private void collateAndHandleBatch( List<RaftMessage<MEMBER>> batch ) | ||
{ | ||
RaftMessages.NewEntry.Batch<MEMBER> batchRequest = null; | ||
|
||
for ( RaftMessage<MEMBER> message : batch ) | ||
{ | ||
if ( message instanceof RaftMessages.NewEntry.Request ) | ||
{ | ||
RaftMessages.NewEntry.Request newEntryRequest = (RaftMessages.NewEntry.Request) message; | ||
|
||
if ( batchRequest == null ) | ||
{ | ||
batchRequest = new RaftMessages.NewEntry.Batch<>( batch.size() ); | ||
} | ||
batchRequest.add( newEntryRequest.content() ); | ||
} | ||
else | ||
{ | ||
innerHandler.handle( message ); | ||
} | ||
} | ||
|
||
if ( batchRequest != null ) | ||
{ | ||
innerHandler.handle( batchRequest ); | ||
} | ||
} | ||
} |
72 changes: 72 additions & 0 deletions
72
enterprise/core-edge/src/main/java/org/neo4j/coreedge/raft/ContinuousJob.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
/* | ||
* Copyright (c) 2002-2016 "Neo Technology," | ||
* Network Engine for Objects in Lund AB [http://neotechnology.com] | ||
* | ||
* This file is part of Neo4j. | ||
* | ||
* Neo4j is free software: you can redistribute it and/or modify | ||
* it under the terms of the GNU Affero General Public License as | ||
* published by the Free Software Foundation, either version 3 of the | ||
* License, or (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU Affero General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU Affero General Public License | ||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
package org.neo4j.coreedge.raft; | ||
|
||
import org.neo4j.kernel.impl.util.JobScheduler; | ||
import org.neo4j.kernel.lifecycle.LifecycleAdapter; | ||
|
||
/** | ||
* Invokes the supplied task continuously when started. The supplied task | ||
* should be short since the abort flag is checked in between invocations. | ||
*/ | ||
public class ContinuousJob extends LifecycleAdapter | ||
{ | ||
private final AbortableJob abortableJob = new AbortableJob(); | ||
private final JobScheduler scheduler; | ||
private final JobScheduler.Group group; | ||
private final Runnable task; | ||
|
||
private JobScheduler.JobHandle jobHandle; | ||
|
||
public ContinuousJob( JobScheduler scheduler, JobScheduler.Group group, Runnable task ) | ||
{ | ||
this.scheduler = scheduler; | ||
this.group = group; | ||
this.task = task; | ||
} | ||
|
||
@Override | ||
public void start() throws Throwable | ||
{ | ||
abortableJob.keepRunning = true; | ||
jobHandle = scheduler.schedule( group, abortableJob ); | ||
} | ||
|
||
@Override | ||
public void stop() throws Throwable | ||
{ | ||
abortableJob.keepRunning = false; | ||
jobHandle.waitTermination(); | ||
} | ||
|
||
private class AbortableJob implements Runnable | ||
{ | ||
private volatile boolean keepRunning; | ||
|
||
@Override | ||
public void run() | ||
{ | ||
while ( keepRunning ) | ||
{ | ||
task.run(); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.