You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@ignite.apache.org by "Alexander Lapin (Jira)" <ji...@apache.org> on 2022/06/28 17:40:00 UTC

[jira] [Updated] (IGNITE-17252) Introduce Replica and ReplicaClient

|  ![](cid:jira-generated-image-avatar-24daba4c-6a86-4209-852b-e01ba4204462) |
[Alexander
Lapin](https://issues.apache.org/jira/secure/ViewProfile.jspa?name=alapin)
**updated** an issue  
---|---  
|  
---  
|  [Ignite](https://issues.apache.org/jira/browse/IGNITE) /
[![Improvement](cid:jira-generated-image-avatar-
ac85cb75-f973-4d01-a982-a9e4b6fe1bba)](https://issues.apache.org/jira/browse/IGNITE-17252)
[IGNITE-17252](https://issues.apache.org/jira/browse/IGNITE-17252)  
---  
[Introduce Replica and
ReplicaClient](https://issues.apache.org/jira/browse/IGNITE-17252)  
| Change By: |  [Alexander
Lapin](https://issues.apache.org/jira/secure/ViewProfile.jspa?name=alapin)  
---|---  
|  According to tx design document new abstraction is introduced to
encapsulate replication engine (e.g. Raft) from business logic, called
{*}primary replica{*}:  
{code:java}  
A primary replica is a replica which serves a special purpose in the
transaction protocol.Only one primary replica can exist at a time. Each
replica is identified by liveness interval (startTs, endTs). All such
intervals are disjoint, so the new primary replica liveness interval can’t
overlap with the previous. Timestamps used for defining the intervals must be
comparable with timestamps assigned to committing transactions. For example,
HLC timestamps can be used for this purpose.  
  
Primary replica is used to execute CC protocol (so all reads and writes go
through it), thus maintaining serializable executions, as described in the
next section.  
  
The simplest implementation would be piggy-backing to RAFT protocol for tying
a primary replica to a RAFT leader. See the leaseholder section from the RAFT
paper for details. For this approach a RAFT leader is identical to a primary
replica node. The endTs is constantly extended using RAFT heart beating.  
  
A primary replica’s status can be voluntarily transferred to another replica.
This is only possible after its liveness interval expires. This can be useful,
for example, for RAFT leaders balancing. {code}  
Besides obvious lease-based disjoint replication leader detection, primary
replica is also responsible for handling messages acting as a storage and
replication pre-and-post-processor. It's up to replica to  
* acquire, release and await locks  
* propagate requests to storage directly  
* convert message to an appropriate replication(Raft) command and propagate it to the replication engine.  
  
Let's check following example:  
  
*As-Is (currently):*  
{code:java}  
// client-side  
InternalTable.upsert()  
    enlistInTx()  
        raftService.run(upsertCommand)  
            raftGroupService.sendWithRetry(ActionRequest.of(upsertCommand))  
               messagingService().invoke(actionRequest)  
  
// server-side  
ActionRequestProcessor.handleRequest(actionRequest)  
   future =
JraftServerImpl.DelegatingStateMachine.getListener().onBeforeApply(request.command());
// Lock management  
   future.handle(actionRequest.command() instanceof WriteCommand ?
applyWrite(actionRequest) : applyRead(actionRequest)){code}  
Please pay attention to *onBeforeApply* step. It was introduced in order to
manage(acquire) locks with further locks awaiting *outside* the raft. It is
critical not to occupy the linearized in-raft execution with such lengthy
operations as waiting for locks to be released.  
  
It worth to mention, that such approach has several disadvantages, e.g.
onBeforeApply step is executed before isLeader() check, so that, it might
acquire lock on  non-leader-node that is not the expected behavior.  
  
*To-Be (should be implemented):*  
{code:java}  
// client-side  
InternalTable.upsert()  
    enlistInTx()  
        replica  
    raftService.run(upsertCommand)  
raftGroupService.sendWithRetry(ActionRequest.of(upsertCommand))  
               messagingService().invoke(actionRequest)  
  
// server-side  
ActionRequestProcessor.handleRequest(actionRequest)  
   future =
JraftServerImpl.DelegatingStateMachine.getListener().onBeforeApply(request.command());
// Lock management  
   future.handle(actionRequest.command() instanceof WriteCommand ?
applyWrite(actionRequest) : applyRead(actionRequest)) {code}  
responsible for handling messages  
  
  
asdasd  
  
  
  
  
---  
|  |  [ ![Add Comment](cid:jira-generated-image-static-comment-
icon-5a6f3c78-e332-4d9c-a258-116e6e2f34bc)
](https://issues.apache.org/jira/browse/IGNITE-17252#add-comment "Add
Comment") |  [Add
Comment](https://issues.apache.org/jira/browse/IGNITE-17252#add-comment "Add
Comment")  
---|---  
  
|  This message was sent by Atlassian Jira (v8.20.10#820010-sha1:ace47f9) |  |
![Atlassian logo](https://issues.apache.org/jira/images/mail/atlassian-email-
logo.png)  
---