bootstrap.go 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. // Copyright 2015 The etcd Authors
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package raft
  15. import (
  16. "errors"
  17. pb "go.etcd.io/etcd/raft/raftpb"
  18. )
  19. // Bootstrap initializes the RawNode for first use by appending configuration
  20. // changes for the supplied peers. This method returns an error if the Storage
  21. // is nonempty.
  22. //
  23. // It is recommended that instead of calling this method, applications bootstrap
  24. // their state manually by setting up a Storage that has a first index > 1 and
  25. // which stores the desired ConfState as its InitialState.
  26. func (rn *RawNode) Bootstrap(peers []Peer) error {
  27. if len(peers) == 0 {
  28. return errors.New("must provide at least one peer to Bootstrap")
  29. }
  30. lastIndex, err := rn.raft.raftLog.storage.LastIndex()
  31. if err != nil {
  32. return err
  33. }
  34. if lastIndex != 0 {
  35. return errors.New("can't bootstrap a nonempty Storage")
  36. }
  37. // We've faked out initial entries above, but nothing has been
  38. // persisted. Start with an empty HardState (thus the first Ready will
  39. // emit a HardState update for the app to persist).
  40. rn.prevHardSt = emptyState
  41. // TODO(tbg): remove StartNode and give the application the right tools to
  42. // bootstrap the initial membership in a cleaner way.
  43. rn.raft.becomeFollower(1, None)
  44. ents := make([]pb.Entry, len(peers))
  45. for i, peer := range peers {
  46. cc := pb.ConfChange{Type: pb.ConfChangeAddNode, NodeID: peer.ID, Context: peer.Context}
  47. data, err := cc.Marshal()
  48. if err != nil {
  49. return err
  50. }
  51. ents[i] = pb.Entry{Type: pb.EntryConfChange, Term: 1, Index: uint64(i + 1), Data: data}
  52. }
  53. rn.raft.raftLog.append(ents...)
  54. // Now apply them, mainly so that the application can call Campaign
  55. // immediately after StartNode in tests. Note that these nodes will
  56. // be added to raft twice: here and when the application's Ready
  57. // loop calls ApplyConfChange. The calls to addNode must come after
  58. // all calls to raftLog.append so progress.next is set after these
  59. // bootstrapping entries (it is an error if we try to append these
  60. // entries since they have already been committed).
  61. // We do not set raftLog.applied so the application will be able
  62. // to observe all conf changes via Ready.CommittedEntries.
  63. //
  64. // TODO(bdarnell): These entries are still unstable; do we need to preserve
  65. // the invariant that committed < unstable?
  66. rn.raft.raftLog.committed = uint64(len(ents))
  67. for _, peer := range peers {
  68. rn.raft.applyConfChange(pb.ConfChange{NodeID: peer.ID, Type: pb.ConfChangeAddNode}.AsV2())
  69. }
  70. return nil
  71. }