log_unstable.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  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 pb "github.com/coreos/etcd/raft/raftpb"
  15. // unstable.entris[i] has raft log position i+unstable.offset.
  16. // Note that unstable.offset may be less than the highest log
  17. // position in storage; this means that the next write to storage
  18. // might need to truncate the log before persisting unstable.entries.
  19. type unstable struct {
  20. // the incoming unstable snapshot, if any.
  21. snapshot *pb.Snapshot
  22. // all entries that have not yet been written to storage.
  23. entries []pb.Entry
  24. offset uint64
  25. }
  26. // maybeFirstIndex returns the first index if it has a snapshot.
  27. func (u *unstable) maybeFirstIndex() (uint64, bool) {
  28. if u.snapshot != nil {
  29. return u.snapshot.Metadata.Index, true
  30. }
  31. return 0, false
  32. }
  33. // maybeLastIndex returns the last index if it has at least one
  34. // unstable entry or snapshot.
  35. func (u *unstable) maybeLastIndex() (uint64, bool) {
  36. if l := len(u.entries); l != 0 {
  37. return u.offset + uint64(l) - 1, true
  38. }
  39. if u.snapshot != nil {
  40. return u.snapshot.Metadata.Index, true
  41. }
  42. return 0, false
  43. }
  44. // myabeTerm returns the term of the entry at index i, if there
  45. // is any.
  46. func (u *unstable) maybeTerm(i uint64) (uint64, bool) {
  47. if i < u.offset {
  48. if u.snapshot == nil {
  49. return 0, false
  50. }
  51. if u.snapshot.Metadata.Index == i {
  52. return u.snapshot.Metadata.Term, true
  53. }
  54. return 0, false
  55. }
  56. last, ok := u.maybeLastIndex()
  57. if !ok {
  58. return 0, false
  59. }
  60. if i > last {
  61. return 0, false
  62. }
  63. return u.entries[i-u.offset].Term, true
  64. }
  65. func (u *unstable) stableTo(i, t uint64) {
  66. gt, ok := u.maybeTerm(i)
  67. if !ok {
  68. return
  69. }
  70. // if i < offest, term is matched with the snapshot
  71. // only update the unstalbe entries if term is matched with
  72. // an unstable entry.
  73. if gt == t && i >= u.offset {
  74. u.entries = u.entries[i+1-u.offset:]
  75. u.offset = i + 1
  76. }
  77. }
  78. func (u *unstable) stableSnapTo(i uint64) {
  79. if u.snapshot != nil && u.snapshot.Metadata.Index == i {
  80. u.snapshot = nil
  81. }
  82. }
  83. func (u *unstable) restore(s pb.Snapshot) {
  84. u.offset = s.Metadata.Index + 1
  85. u.entries = nil
  86. u.snapshot = &s
  87. }
  88. func (u *unstable) truncateAndAppend(after uint64, ents []pb.Entry) {
  89. switch {
  90. case after < u.offset:
  91. // The log is being truncated to before our current offset
  92. // portion, so set the offset and replace the entries
  93. u.offset = after + 1
  94. u.entries = ents
  95. case after == u.offset+uint64(len(u.entries))-1:
  96. // after is the last index in the u.entries
  97. // directly append
  98. u.entries = append(u.entries, ents...)
  99. default:
  100. // truncate to after and copy to u.entries
  101. // then append
  102. u.entries = append([]pb.Entry{}, u.slice(u.offset, after+1)...)
  103. u.entries = append(u.entries, ents...)
  104. }
  105. }
  106. func (u *unstable) slice(lo uint64, hi uint64) []pb.Entry {
  107. if lo >= hi {
  108. return nil
  109. }
  110. if u.isOutOfBounds(lo) || u.isOutOfBounds(hi-1) {
  111. return nil
  112. }
  113. return u.entries[lo-u.offset : hi-u.offset]
  114. }
  115. func (u *unstable) isOutOfBounds(i uint64) bool {
  116. if len(u.entries) == 0 {
  117. return true
  118. }
  119. last := u.offset + uint64(len(u.entries)) - 1
  120. if i < u.offset || i > last {
  121. return true
  122. }
  123. return false
  124. }