2 * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.controller.cluster.raft.messages;
11 import com.google.protobuf.GeneratedMessage;
12 import org.opendaylight.controller.cluster.raft.ReplicatedLogEntry;
13 import org.opendaylight.controller.cluster.raft.ReplicatedLogImplEntry;
14 import org.opendaylight.controller.cluster.raft.protobuff.client.messages.Payload;
15 import org.opendaylight.controller.cluster.raft.protobuff.messages.AppendEntriesMessages;
17 import java.util.ArrayList;
18 import java.util.Iterator;
19 import java.util.List;
23 * Invoked by leader to replicate log entries (§5.3); also used as
26 public class AppendEntries extends AbstractRaftRPC {
28 public static final Class SERIALIZABLE_CLASS = AppendEntriesMessages.AppendEntries.class;
30 private static final org.slf4j.Logger LOG = org.slf4j.LoggerFactory.getLogger(AppendEntries.class);
32 // So that follower can redirect clients
33 private final String leaderId;
35 // Index of log entry immediately preceding new ones
36 private final long prevLogIndex;
38 // term of prevLogIndex entry
39 private final long prevLogTerm;
41 // log entries to store (empty for heartbeat;
42 // may send more than one for efficiency)
43 private final List<ReplicatedLogEntry> entries;
45 // leader's commitIndex
46 private final long leaderCommit;
48 public AppendEntries(long term, String leaderId, long prevLogIndex,
49 long prevLogTerm, List<ReplicatedLogEntry> entries, long leaderCommit) {
51 this.leaderId = leaderId;
52 this.prevLogIndex = prevLogIndex;
53 this.prevLogTerm = prevLogTerm;
54 this.entries = entries;
55 this.leaderCommit = leaderCommit;
58 public String getLeaderId() {
62 public long getPrevLogIndex() {
66 public long getPrevLogTerm() {
70 public List<ReplicatedLogEntry> getEntries() {
74 public long getLeaderCommit() {
78 @Override public String toString() {
79 final StringBuilder sb =
80 new StringBuilder("AppendEntries{");
81 sb.append("term=").append(getTerm());
82 sb.append("leaderId='").append(leaderId).append('\'');
83 sb.append(", prevLogIndex=").append(prevLogIndex);
84 sb.append(", prevLogTerm=").append(prevLogTerm);
85 sb.append(", entries=").append(entries);
86 sb.append(", leaderCommit=").append(leaderCommit);
91 public <T extends Object> Object toSerializable(){
92 AppendEntriesMessages.AppendEntries.Builder to = AppendEntriesMessages.AppendEntries.newBuilder();
93 to.setTerm(this.getTerm())
94 .setLeaderId(this.getLeaderId())
95 .setPrevLogTerm(this.getPrevLogTerm())
96 .setPrevLogIndex(this.getPrevLogIndex())
97 .setLeaderCommit(this.getLeaderCommit());
99 for (ReplicatedLogEntry logEntry : this.getEntries()) {
101 AppendEntriesMessages.AppendEntries.ReplicatedLogEntry.Builder arBuilder =
102 AppendEntriesMessages.AppendEntries.ReplicatedLogEntry.newBuilder();
104 AppendEntriesMessages.AppendEntries.ReplicatedLogEntry.Payload.Builder arpBuilder =
105 AppendEntriesMessages.AppendEntries.ReplicatedLogEntry.Payload.newBuilder();
107 //get the client specific payload extensions and add them to the payload builder
108 Map<GeneratedMessage.GeneratedExtension, T> map = logEntry.getData().encode();
109 Iterator<Map.Entry<GeneratedMessage.GeneratedExtension, T>> iter = map.entrySet().iterator();
111 while (iter.hasNext()) {
112 Map.Entry<GeneratedMessage.GeneratedExtension, T> entry = iter.next();
113 arpBuilder.setExtension(entry.getKey(), entry.getValue());
116 arpBuilder.setClientPayloadClassName(logEntry.getData().getClientPayloadClassName());
118 arBuilder.setData(arpBuilder).setIndex(logEntry.getIndex()).setTerm(logEntry.getTerm());
119 to.addLogEntries(arBuilder);
125 public static AppendEntries fromSerializable(Object o){
126 AppendEntriesMessages.AppendEntries from = (AppendEntriesMessages.AppendEntries) o;
128 List<ReplicatedLogEntry> logEntryList = new ArrayList<>();
129 for (AppendEntriesMessages.AppendEntries.ReplicatedLogEntry leProtoBuff : from.getLogEntriesList()) {
131 Payload payload = null ;
133 if(leProtoBuff.getData() != null && leProtoBuff.getData().getClientPayloadClassName() != null) {
134 String clientPayloadClassName = leProtoBuff.getData().getClientPayloadClassName();
135 payload = (Payload)Class.forName(clientPayloadClassName).newInstance();
136 payload = payload.decode(leProtoBuff.getData());
137 payload.setClientPayloadClassName(clientPayloadClassName);
139 LOG.error("Payload is null or payload does not have client payload class name");
142 } catch (InstantiationException e) {
143 LOG.error("InstantiationException when instantiating "+leProtoBuff.getData().getClientPayloadClassName(), e);
144 } catch (IllegalAccessException e) {
145 LOG.error("IllegalAccessException when accessing "+leProtoBuff.getData().getClientPayloadClassName(), e);
146 } catch (ClassNotFoundException e) {
147 LOG.error("ClassNotFoundException when loading "+leProtoBuff.getData().getClientPayloadClassName(), e);
149 ReplicatedLogEntry logEntry = new ReplicatedLogImplEntry(
150 leProtoBuff.getIndex(), leProtoBuff.getTerm(), payload);
151 logEntryList.add(logEntry);
154 AppendEntries to = new AppendEntries(from.getTerm(),
156 from.getPrevLogIndex(),
157 from.getPrevLogTerm(),
159 from.getLeaderCommit());