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 java.util.Collection;
14  import java.util.Map;
15  
16  import org.eclipse.jgit.annotations.Nullable;
17  import org.eclipse.jgit.lib.Ref;
18  import org.eclipse.jgit.lib.Repository;
19  import org.eclipse.jgit.transport.ReceiveCommand;
20  
21  /**
22   * A push request sending objects to a replica, and its result.
23   * <p>
24   * Implementors of {@link org.eclipse.jgit.internal.ketch.KetchReplica} must
25   * populate the command result fields, {@link #setRefs(Map)}, and call one of
26   * {@link #setException(Repository, Throwable)} or {@link #done(Repository)} to
27   * finish processing.
28   */
29  public class ReplicaPushRequest {
30  	private final KetchReplica replica;
31  	private final Collection<ReceiveCommand> commands;
32  	private Map<String, Ref> refs;
33  	private Throwable exception;
34  	private boolean notified;
35  
36  	/**
37  	 * Construct a new push request for a replica.
38  	 *
39  	 * @param replica
40  	 *            the replica being pushed to.
41  	 * @param commands
42  	 *            commands to be executed.
43  	 */
44  	public ReplicaPushRequest(KetchReplica replica,
45  			Collection<ReceiveCommand> commands) {
46  		this.replica = replica;
47  		this.commands = commands;
48  	}
49  
50  	/**
51  	 * Get commands to be executed, and their results.
52  	 *
53  	 * @return commands to be executed, and their results.
54  	 */
55  	public Collection<ReceiveCommand> getCommands() {
56  		return commands;
57  	}
58  
59  	/**
60  	 * Get remote references, usually from the advertisement.
61  	 *
62  	 * @return remote references, usually from the advertisement.
63  	 */
64  	@Nullable
65  	public Map<String, Ref> getRefs() {
66  		return refs;
67  	}
68  
69  	/**
70  	 * Set references observed from the replica.
71  	 *
72  	 * @param refs
73  	 *            references observed from the replica.
74  	 */
75  	public void setRefs(Map<String, Ref> refs) {
76  		this.refs = refs;
77  	}
78  
79  	/**
80  	 * Get exception thrown, if any.
81  	 *
82  	 * @return exception thrown, if any.
83  	 */
84  	@Nullable
85  	public Throwable getException() {
86  		return exception;
87  	}
88  
89  	/**
90  	 * Mark the request as crashing with a communication error.
91  	 * <p>
92  	 * This method may take significant time acquiring the leader lock and
93  	 * updating the Ketch state machine with the failure.
94  	 *
95  	 * @param repo
96  	 *            local repository reference used by the push attempt.
97  	 * @param err
98  	 *            exception thrown during communication.
99  	 */
100 	public void setException(@Nullable Repository repo, Throwable err) {
101 		if (KetchReplica.log.isErrorEnabled()) {
102 			KetchReplica.log.error(describe("failed"), err); //$NON-NLS-1$
103 		}
104 		if (!notified) {
105 			notified = true;
106 			exception = err;
107 			replica.afterPush(repo, this);
108 		}
109 	}
110 
111 	/**
112 	 * Mark the request as completed without exception.
113 	 * <p>
114 	 * This method may take significant time acquiring the leader lock and
115 	 * updating the Ketch state machine with results from this replica.
116 	 *
117 	 * @param repo
118 	 *            local repository reference used by the push attempt.
119 	 */
120 	public void done(Repository repo) {
121 		if (KetchReplica.log.isDebugEnabled()) {
122 			KetchReplica.log.debug(describe("completed")); //$NON-NLS-1$
123 		}
124 		if (!notified) {
125 			notified = true;
126 			replica.afterPush(repo, this);
127 		}
128 	}
129 
130 	private String describe(String heading) {
131 		StringBuilder b = new StringBuilder();
132 		b.append("push to "); //$NON-NLS-1$
133 		b.append(replica.describeForLog());
134 		b.append(' ').append(heading).append(":\n"); //$NON-NLS-1$
135 		for (ReceiveCommand cmd : commands) {
136 			b.append(String.format(
137 					"  %-12s %-12s %s %s", //$NON-NLS-1$
138 					LeaderSnapshot.str(cmd.getOldId()),
139 					LeaderSnapshot.str(cmd.getNewId()),
140 					cmd.getRefName(),
141 					cmd.getResult()));
142 			if (cmd.getMessage() != null) {
143 				b.append(' ').append(cmd.getMessage());
144 			}
145 			b.append('\n');
146 		}
147 		return b.toString();
148 	}
149 }