You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ElectionRound.java 3.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  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. package org.eclipse.jgit.internal.ketch;
  11. import static java.util.concurrent.TimeUnit.SECONDS;
  12. import static org.eclipse.jgit.internal.ketch.KetchConstants.TERM;
  13. import java.io.IOException;
  14. import java.util.List;
  15. import java.util.concurrent.TimeoutException;
  16. import org.eclipse.jgit.lib.CommitBuilder;
  17. import org.eclipse.jgit.lib.ObjectId;
  18. import org.eclipse.jgit.lib.ObjectInserter;
  19. import org.eclipse.jgit.lib.Repository;
  20. import org.eclipse.jgit.lib.TreeFormatter;
  21. import org.eclipse.jgit.revwalk.RevCommit;
  22. import org.eclipse.jgit.revwalk.RevWalk;
  23. import org.eclipse.jgit.util.time.ProposedTimestamp;
  24. import org.slf4j.Logger;
  25. import org.slf4j.LoggerFactory;
  26. /**
  27. * The initial {@link Round} for a leaderless repository, used to establish a
  28. * leader.
  29. */
  30. class ElectionRound extends Round {
  31. private static final Logger log = LoggerFactory.getLogger(ElectionRound.class);
  32. private long term;
  33. ElectionRound(KetchLeader leader, LogIndex head) {
  34. super(leader, head);
  35. }
  36. @Override
  37. void start() throws IOException {
  38. ObjectId id;
  39. try (Repository git = leader.openRepository();
  40. ProposedTimestamp ts = getSystem().getClock().propose();
  41. ObjectInserter inserter = git.newObjectInserter()) {
  42. id = bumpTerm(git, ts, inserter);
  43. inserter.flush();
  44. blockUntil(ts);
  45. }
  46. runAsync(id);
  47. }
  48. @Override
  49. void success() {
  50. // Do nothing upon election, KetchLeader will copy the term.
  51. }
  52. long getTerm() {
  53. return term;
  54. }
  55. private ObjectId bumpTerm(Repository git, ProposedTimestamp ts,
  56. ObjectInserter inserter) throws IOException {
  57. CommitBuilder b = new CommitBuilder();
  58. if (!ObjectId.zeroId().equals(acceptedOldIndex)) {
  59. try (RevWalk rw = new RevWalk(git)) {
  60. RevCommit c = rw.parseCommit(acceptedOldIndex);
  61. if (getSystem().requireMonotonicLeaderElections()) {
  62. if (ts.read(SECONDS) < c.getCommitTime()) {
  63. throw new TimeIsUncertainException();
  64. }
  65. }
  66. b.setTreeId(c.getTree());
  67. b.setParentId(acceptedOldIndex);
  68. term = parseTerm(c.getFooterLines(TERM)) + 1;
  69. }
  70. } else {
  71. term = 1;
  72. b.setTreeId(inserter.insert(new TreeFormatter()));
  73. }
  74. StringBuilder msg = new StringBuilder();
  75. msg.append(KetchConstants.TERM.getName())
  76. .append(": ") //$NON-NLS-1$
  77. .append(term);
  78. String tag = leader.getSystem().newLeaderTag();
  79. if (tag != null && !tag.isEmpty()) {
  80. msg.append(' ').append(tag);
  81. }
  82. b.setAuthor(leader.getSystem().newCommitter(ts));
  83. b.setCommitter(b.getAuthor());
  84. b.setMessage(msg.toString());
  85. if (log.isDebugEnabled()) {
  86. log.debug("Trying to elect myself " + b.getMessage()); //$NON-NLS-1$
  87. }
  88. return inserter.insert(b);
  89. }
  90. private static long parseTerm(List<String> footer) {
  91. if (footer.isEmpty()) {
  92. return 0;
  93. }
  94. String s = footer.get(0);
  95. int p = s.indexOf(' ');
  96. if (p > 0) {
  97. s = s.substring(0, p);
  98. }
  99. return Long.parseLong(s, 10);
  100. }
  101. private void blockUntil(ProposedTimestamp ts) throws IOException {
  102. try {
  103. ts.blockUntil(getSystem().getMaxWaitForMonotonicClock());
  104. } catch (InterruptedException | TimeoutException e) {
  105. throw new TimeIsUncertainException(e);
  106. }
  107. }
  108. }