log_unstable.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. /*
  2. Copyright 2014 CoreOS, Inc.
  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. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package raft
  14. import (
  15. "log"
  16. pb "github.com/coreos/etcd/raft/raftpb"
  17. )
  18. // unstable.entris[i] has raft log position i+unstable.offset.
  19. // Note that unstable.offset may be less than the highest log
  20. // position in storage; this means that the next write to storage
  21. // might need to truncate the log before persisting unstable.entries.
  22. type unstable struct {
  23. // the incoming unstable snapshot, if any.
  24. snapshot *pb.Snapshot
  25. // all entries that have not yet been written to storage.
  26. entries []pb.Entry
  27. offset uint64
  28. }
  29. // maybeFirstIndex returns the first index if it has a snapshot.
  30. func (u *unstable) maybeFirstIndex() (uint64, bool) {
  31. if u.snapshot != nil {
  32. return u.snapshot.Metadata.Index, true
  33. }
  34. return 0, false
  35. }
  36. // maybeLastIndex returns the last index if it has at least one
  37. // unstable entry or snapshot.
  38. func (u *unstable) maybeLastIndex() (uint64, bool) {
  39. if l := len(u.entries); l != 0 {
  40. return u.offset + uint64(l) - 1, true
  41. }
  42. if u.snapshot != nil {
  43. return u.snapshot.Metadata.Index, true
  44. }
  45. return 0, false
  46. }
  47. // myabeTerm returns the term of the entry at index i, if there
  48. // is any.
  49. func (u *unstable) maybeTerm(i uint64) (uint64, bool) {
  50. if i < u.offset {
  51. if u.snapshot == nil {
  52. return 0, false
  53. }
  54. if u.snapshot.Metadata.Index == i {
  55. return u.snapshot.Metadata.Term, true
  56. }
  57. return 0, false
  58. }
  59. last, ok := u.maybeLastIndex()
  60. if !ok {
  61. return 0, false
  62. }
  63. if i > last {
  64. return 0, false
  65. }
  66. return u.entries[i-u.offset].Term, true
  67. }
  68. func (u *unstable) stableTo(i, t uint64) {
  69. gt, ok := u.maybeTerm(i)
  70. if !ok {
  71. return
  72. }
  73. // if i < offest, term is matched with the snapshot
  74. // only update the unstalbe entries if term is matched with
  75. // an unstable entry.
  76. if gt == t && i >= u.offset {
  77. u.entries = u.entries[i+1-u.offset:]
  78. u.offset = i + 1
  79. }
  80. }
  81. func (u *unstable) stableSnapTo(i uint64) {
  82. if u.snapshot != nil && u.snapshot.Metadata.Index == i {
  83. u.snapshot = nil
  84. }
  85. }
  86. func (u *unstable) restore(s pb.Snapshot) {
  87. u.offset = s.Metadata.Index + 1
  88. u.entries = nil
  89. u.snapshot = &s
  90. }
  91. func (u *unstable) truncateAndAppend(after uint64, ents []pb.Entry) {
  92. switch {
  93. case after == u.offset+uint64(len(u.entries))-1:
  94. // after is the last index in the u.entries
  95. // directly append
  96. u.entries = append(u.entries, ents...)
  97. case after < u.offset:
  98. log.Printf("raftlog: replace the unstable entries from index %d", after+1)
  99. // The log is being truncated to before our current offset
  100. // portion, so set the offset and replace the entries
  101. u.offset = after + 1
  102. u.entries = ents
  103. default:
  104. // truncate to after and copy to u.entries
  105. // then append
  106. log.Printf("raftlog: truncate the unstable entries to index %d", after)
  107. u.entries = append([]pb.Entry{}, u.slice(u.offset, after+1)...)
  108. u.entries = append(u.entries, ents...)
  109. }
  110. }
  111. func (u *unstable) slice(lo uint64, hi uint64) []pb.Entry {
  112. if lo >= hi {
  113. return nil
  114. }
  115. if u.isOutOfBounds(lo) || u.isOutOfBounds(hi-1) {
  116. return nil
  117. }
  118. return u.entries[lo-u.offset : hi-u.offset]
  119. }
  120. func (u *unstable) isOutOfBounds(i uint64) bool {
  121. if len(u.entries) == 0 {
  122. return true
  123. }
  124. last := u.offset + uint64(len(u.entries)) - 1
  125. if i < u.offset || i > last {
  126. return true
  127. }
  128. return false
  129. }