These are chat archives for atomix/atomix

8th
Aug 2016
terrytan
@txm119161336_twitter
Aug 08 2016 02:05
hi , i found a problem with copycat , could any one help me on this?
Jordan Halterman
@kuujo
Aug 08 2016 02:17
sure
terrytan
@txm119161336_twitter
Aug 08 2016 02:45
I found the codes in method applyCommand
try (CommandEntry entry = context.getLog().create(CommandEntry.class)) {
Jordan Halterman
@kuujo
Aug 08 2016 02:46
sorry I’m putting my kid to sleep but I’m paying attention
terrytan
@txm119161336_twitter
Aug 08 2016 02:46
if we have concurrent requests , there will be thread safety problem, the index generated might be the duplicatedd
Thank you for your help , say good night to your kid for me
Jordan Halterman
@kuujo
Aug 08 2016 03:15
K all done...
terrytan
@txm119161336_twitter
Aug 08 2016 03:17
ok, like above code , if we have concurrent requests, the index generated will be duplicated
Jordan Halterman
@kuujo
Aug 08 2016 03:20
Correct... The reason you're seeing code that's not thread safe inside the Copycat server is because virtually none of the code is thread safe, and that's an intentional design decision. The server actually serialized requests on a single thread. That removes the need for much locking and is largely necessary to enforce order throughout the server. That's not to say the server is single threaded. There are actually many threads in the server, but requests take a deterministic route through those threads that ensures everything happens in a specific order as is required by the algorithm.
Very few server related objects are thread safe. Only certain parts of the log are thread safe to allow the replication and log compaction algorithms to operate on the log concurrently.
The threading for the methods you're looking at is handled in the transport, which is not where t should be. Currently, the NettyTransport ensures that messages are received on the correct thread.
You'll see throughout the code this line: context.checkThread(). That is a call that is ensuring the code is being executed on the server thread and thus does not need locks
Each unique thread has a context, and various parts of the code use it to ensure they're being executed on the correct thread. The Executor framework is used to switch threads e.g. in the state machine or compaction threads.
This pattern comes from Vert.x, to which I was a major contributor in the past
Jordan Halterman
@kuujo
Aug 08 2016 03:27
I've experimented a bit with handling requests on different threads and serializing log access on another thread through a queue, but performance has always suffered quite a bit.
terrytan
@txm119161336_twitter
Aug 08 2016 03:28
raft uses the index to track the replica and other things, if the index is duplicated , how do we handle the replica?
terrytan
@txm119161336_twitter
Aug 08 2016 03:34
i mean even if it is thread safe , they share the same log in the same segment,if the index is duplicated , how do we deal with this thing?
Jordan Halterman
@kuujo
Aug 08 2016 03:41
How would the index be duplicated? I've never seen that and it should be impossible
Appends to the log always occur on the same thread, and an entry is always appended before returning, so two entries cannot get the same index
When the entry is created it has the next index, is populated, and is appended before the method call returns. If the method were called concurrently it would be possible for two entries to have the same index, but that is not allowed through thread checks.
terrytan
@txm119161336_twitter
Aug 08 2016 04:23
which means actually almost all the log related handling are finished in a single thread , before the method returning ,another command can not be processed ?
Jordan Halterman
@kuujo
Aug 08 2016 04:25
Indeed
terrytan
@txm119161336_twitter
Aug 08 2016 04:29
if as what you said ,the implementation at the bottom level, all the command s will be in a queue? just like a thread pool, which will retrieve tasks from the queue , but you said it is not like queue, so i am confused about this
or it is just like redis , is a loop for ?
Jordan Halterman
@kuujo
Aug 08 2016 07:04
I didn’t say it’s not like a queue. Copycat uses the Executor framework, which uses queues. When a message is received by the NettyTransport, it uses the appropriate single threaded Executor which enqueues the command to be handled on the server thread which writes to the log.
I experimented with adding additional threads to e.g. handle client requests on x threads and server-to-server requests on y threads and queue them for writes to the log but performance suffered
terrytan
@txm119161336_twitter
Aug 08 2016 09:36
now i understand , i have seen ScheduledThreadPoolExecutor。
the bottom level is a ScheduledExecutorService , that is your implementation ?
Jordan Halterman
@kuujo
Aug 08 2016 11:13
I think ScheduledExecutorService is an interface... Executors.newSingleThreadScheduledExecutor() basically just returns a ScheduledThreadPoolExecutor with a pool size of 1 IIRC. Looks like Catalyst just uses the constructor: https://github.com/atomix/catalyst/blob/master/concurrent/src/main/java/io/atomix/catalyst/concurrent/SingleThreadContext.java
terrytan
@txm119161336_twitter
Aug 08 2016 11:30
Thank you so much
Jordan Halterman
@kuujo
Aug 08 2016 17:46
np