View Javadoc
1   /*
2    * Copyright (C) 2016, Google Inc. and others
3    *
4    * This program and the accompanying materials are made available under the
5    * terms of the Eclipse Distribution License v. 1.0 which is available at
6    * https://www.eclipse.org/org/documents/edl-v10.php.
7    *
8    * SPDX-License-Identifier: BSD-3-Clause
9    */
10  
11  package org.eclipse.jgit.internal.ketch;
12  
13  import static org.eclipse.jgit.internal.ketch.KetchReplica.State.OFFLINE;
14  
15  import java.util.ArrayList;
16  import java.util.Collection;
17  import java.util.Collections;
18  import java.util.List;
19  
20  import org.eclipse.jgit.annotations.Nullable;
21  import org.eclipse.jgit.lib.ObjectId;
22  
23  /**
24   * A snapshot of a leader and its view of the world.
25   */
26  public class LeaderSnapshot {
27  	final List<ReplicaSnapshot> replicas = new ArrayList<>();
28  	KetchLeader.State state;
29  	long term;
30  	LogIndex headIndex;
31  	LogIndex committedIndex;
32  	boolean idle;
33  
34  	LeaderSnapshot() {
35  	}
36  
37  	/**
38  	 * Get unmodifiable view of configured replicas.
39  	 *
40  	 * @return unmodifiable view of configured replicas.
41  	 */
42  	public Collection<ReplicaSnapshot> getReplicas() {
43  		return Collections.unmodifiableList(replicas);
44  	}
45  
46  	/**
47  	 * Get current state of the leader.
48  	 *
49  	 * @return current state of the leader.
50  	 */
51  	public KetchLeader.State getState() {
52  		return state;
53  	}
54  
55  	/**
56  	 * Whether the leader is not running a round to reach consensus, and has no
57  	 * rounds queued.
58  	 *
59  	 * @return {@code true} if the leader is not running a round to reach
60  	 *         consensus, and has no rounds queued.
61  	 */
62  	public boolean isIdle() {
63  		return idle;
64  	}
65  
66  	/**
67  	 * Get term of this leader
68  	 *
69  	 * @return term of this leader. Valid only if {@link #getState()} is
70  	 *         currently
71  	 *         {@link org.eclipse.jgit.internal.ketch.KetchLeader.State#LEADER}.
72  	 */
73  	public long getTerm() {
74  		return term;
75  	}
76  
77  	/**
78  	 * Get end of the leader's log
79  	 *
80  	 * @return end of the leader's log; null if leader hasn't started up enough
81  	 *         to begin its own election.
82  	 */
83  	@Nullable
84  	public LogIndex getHead() {
85  		return headIndex;
86  	}
87  
88  	/**
89  	 * Get state the leader knows is committed on a majority of participant
90  	 * replicas
91  	 *
92  	 * @return state the leader knows is committed on a majority of participant
93  	 *         replicas. Null until the leader instance has committed a log
94  	 *         index within its own term.
95  	 */
96  	@Nullable
97  	public LogIndex getCommitted() {
98  		return committedIndex;
99  	}
100 
101 	/** {@inheritDoc} */
102 	@Override
103 	public String toString() {
104 		StringBuilder s = new StringBuilder();
105 		s.append(isIdle() ? "IDLE" : "RUNNING"); //$NON-NLS-1$ //$NON-NLS-2$
106 		s.append(" state ").append(getState()); //$NON-NLS-1$
107 		if (getTerm() > 0) {
108 			s.append(" term ").append(getTerm()); //$NON-NLS-1$
109 		}
110 		s.append('\n');
111 		s.append(String.format(
112 				"%-10s %12s %12s\n", //$NON-NLS-1$
113 				"Replica", "Accepted", "Committed")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
114 		s.append("------------------------------------\n"); //$NON-NLS-1$
115 		debug(s, "(leader)", getHead(), getCommitted()); //$NON-NLS-1$
116 		s.append('\n');
117 		for (ReplicaSnapshot r : getReplicas()) {
118 			debug(s, r);
119 			s.append('\n');
120 		}
121 		s.append('\n');
122 		return s.toString();
123 	}
124 
125 	private static void debug(StringBuilder b, ReplicaSnapshot s) {
126 		KetchReplica replica = s.getReplica();
127 		debug(b, replica.getName(), s.getAccepted(), s.getCommitted());
128 		b.append(String.format(" %-8s %s", //$NON-NLS-1$
129 				replica.getParticipation(), s.getState()));
130 		if (s.getState() == OFFLINE) {
131 			String err = s.getErrorMessage();
132 			if (err != null) {
133 				b.append(" (").append(err).append(')'); //$NON-NLS-1$
134 			}
135 		}
136 	}
137 
138 	private static void debug(StringBuilder s, String name,
139 			ObjectId accepted, ObjectId committed) {
140 		s.append(String.format(
141 				"%-10s %-12s %-12s", //$NON-NLS-1$
142 				name, str(accepted), str(committed)));
143 	}
144 
145 	static String str(ObjectId c) {
146 		if (c instanceof LogIndex) {
147 			return ((LogIndex) c).describeForLog();
148 		} else if (c != null) {
149 			return c.abbreviate(8).name();
150 		}
151 		return "-"; //$NON-NLS-1$
152 	}
153 }