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 org.eclipse.jgit.lib.AnyObjectId;
14 import org.eclipse.jgit.lib.ObjectId;
15
16 /**
17 * An ObjectId for a commit extended with incrementing log index.
18 * <p>
19 * For any two LogIndex instances, {@code A} is an ancestor of {@code C}
20 * reachable through parent edges in the graph if {@code A.index < C.index}.
21 * LogIndex provides a performance optimization for Ketch, the same information
22 * can be obtained from {@link org.eclipse.jgit.revwalk.RevWalk}.
23 * <p>
24 * Index values are only valid within a single
25 * {@link org.eclipse.jgit.internal.ketch.KetchLeader} instance after it has won
26 * an election. By restricting scope to a single leader new leaders do not need
27 * to traverse the entire history to determine the next {@code index} for new
28 * proposals. This differs from Raft, where leader election uses the log index
29 * and the term number to determine which replica holds a sufficiently
30 * up-to-date log. Since Ketch uses Git objects for storage of its replicated
31 * log, it keeps the term number as Raft does but uses standard Git operations
32 * to imply the log index.
33 * <p>
34 * {@link org.eclipse.jgit.internal.ketch.Round#runAsync(AnyObjectId)} bumps the
35 * index as each new round is constructed.
36 */
37 public class LogIndex extends ObjectId {
38 static LogIndex unknown(AnyObjectId id) {
39 return new LogIndex(id, 0);
40 }
41
42 private final long index;
43
44 private LogIndex(AnyObjectId id, long index) {
45 super(id);
46 this.index = index;
47 }
48
49 LogIndex nextIndex(AnyObjectId id) {
50 return new LogIndex(id, index + 1);
51 }
52
53 /**
54 * Get index provided by the current leader instance.
55 *
56 * @return index provided by the current leader instance.
57 */
58 public long getIndex() {
59 return index;
60 }
61
62 /**
63 * Check if this log position committed before another log position.
64 * <p>
65 * Only valid for log positions in memory for the current leader.
66 *
67 * @param c
68 * other (more recent) log position.
69 * @return true if this log position was before {@code c} or equal to c and
70 * therefore any agreement of {@code c} implies agreement on this
71 * log position.
72 */
73 boolean isBefore(LogIndex c) {
74 return index <= c.index;
75 }
76
77 /**
78 * Create string suitable for debug logging containing the log index and
79 * abbreviated ObjectId.
80 *
81 * @return string suitable for debug logging containing the log index and
82 * abbreviated ObjectId.
83 */
84 @SuppressWarnings("boxing")
85 public String describeForLog() {
86 return String.format("%5d/%s", index, abbreviate(6).name()); //$NON-NLS-1$
87 }
88
89 /** {@inheritDoc} */
90 @SuppressWarnings("boxing")
91 @Override
92 public String toString() {
93 return String.format("LogId[%5d/%s]", index, name()); //$NON-NLS-1$
94 }
95 }