With CoreDNS now supporting etcdv3 as the DNS backend, we can update our federation target to etcdv3. Users will now be able to use etcdv3 server as the federation backbone. Minio will update bucket data to etcdv3 and CoreDNS can pick that data up and serve it as bucket style DNS path.
159 lines
4.7 KiB
Go
159 lines
4.7 KiB
Go
// Copyright 2015 The etcd Authors
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package raft
|
|
|
|
import pb "github.com/coreos/etcd/raft/raftpb"
|
|
|
|
// unstable.entries[i] has raft log position i+unstable.offset.
|
|
// Note that unstable.offset may be less than the highest log
|
|
// position in storage; this means that the next write to storage
|
|
// might need to truncate the log before persisting unstable.entries.
|
|
type unstable struct {
|
|
// the incoming unstable snapshot, if any.
|
|
snapshot *pb.Snapshot
|
|
// all entries that have not yet been written to storage.
|
|
entries []pb.Entry
|
|
offset uint64
|
|
|
|
logger Logger
|
|
}
|
|
|
|
// maybeFirstIndex returns the index of the first possible entry in entries
|
|
// if it has a snapshot.
|
|
func (u *unstable) maybeFirstIndex() (uint64, bool) {
|
|
if u.snapshot != nil {
|
|
return u.snapshot.Metadata.Index + 1, true
|
|
}
|
|
return 0, false
|
|
}
|
|
|
|
// maybeLastIndex returns the last index if it has at least one
|
|
// unstable entry or snapshot.
|
|
func (u *unstable) maybeLastIndex() (uint64, bool) {
|
|
if l := len(u.entries); l != 0 {
|
|
return u.offset + uint64(l) - 1, true
|
|
}
|
|
if u.snapshot != nil {
|
|
return u.snapshot.Metadata.Index, true
|
|
}
|
|
return 0, false
|
|
}
|
|
|
|
// maybeTerm returns the term of the entry at index i, if there
|
|
// is any.
|
|
func (u *unstable) maybeTerm(i uint64) (uint64, bool) {
|
|
if i < u.offset {
|
|
if u.snapshot == nil {
|
|
return 0, false
|
|
}
|
|
if u.snapshot.Metadata.Index == i {
|
|
return u.snapshot.Metadata.Term, true
|
|
}
|
|
return 0, false
|
|
}
|
|
|
|
last, ok := u.maybeLastIndex()
|
|
if !ok {
|
|
return 0, false
|
|
}
|
|
if i > last {
|
|
return 0, false
|
|
}
|
|
return u.entries[i-u.offset].Term, true
|
|
}
|
|
|
|
func (u *unstable) stableTo(i, t uint64) {
|
|
gt, ok := u.maybeTerm(i)
|
|
if !ok {
|
|
return
|
|
}
|
|
// if i < offset, term is matched with the snapshot
|
|
// only update the unstable entries if term is matched with
|
|
// an unstable entry.
|
|
if gt == t && i >= u.offset {
|
|
u.entries = u.entries[i+1-u.offset:]
|
|
u.offset = i + 1
|
|
u.shrinkEntriesArray()
|
|
}
|
|
}
|
|
|
|
// shrinkEntriesArray discards the underlying array used by the entries slice
|
|
// if most of it isn't being used. This avoids holding references to a bunch of
|
|
// potentially large entries that aren't needed anymore. Simply clearing the
|
|
// entries wouldn't be safe because clients might still be using them.
|
|
func (u *unstable) shrinkEntriesArray() {
|
|
// We replace the array if we're using less than half of the space in
|
|
// it. This number is fairly arbitrary, chosen as an attempt to balance
|
|
// memory usage vs number of allocations. It could probably be improved
|
|
// with some focused tuning.
|
|
const lenMultiple = 2
|
|
if len(u.entries) == 0 {
|
|
u.entries = nil
|
|
} else if len(u.entries)*lenMultiple < cap(u.entries) {
|
|
newEntries := make([]pb.Entry, len(u.entries))
|
|
copy(newEntries, u.entries)
|
|
u.entries = newEntries
|
|
}
|
|
}
|
|
|
|
func (u *unstable) stableSnapTo(i uint64) {
|
|
if u.snapshot != nil && u.snapshot.Metadata.Index == i {
|
|
u.snapshot = nil
|
|
}
|
|
}
|
|
|
|
func (u *unstable) restore(s pb.Snapshot) {
|
|
u.offset = s.Metadata.Index + 1
|
|
u.entries = nil
|
|
u.snapshot = &s
|
|
}
|
|
|
|
func (u *unstable) truncateAndAppend(ents []pb.Entry) {
|
|
after := ents[0].Index
|
|
switch {
|
|
case after == u.offset+uint64(len(u.entries)):
|
|
// after is the next index in the u.entries
|
|
// directly append
|
|
u.entries = append(u.entries, ents...)
|
|
case after <= u.offset:
|
|
u.logger.Infof("replace the unstable entries from index %d", after)
|
|
// The log is being truncated to before our current offset
|
|
// portion, so set the offset and replace the entries
|
|
u.offset = after
|
|
u.entries = ents
|
|
default:
|
|
// truncate to after and copy to u.entries
|
|
// then append
|
|
u.logger.Infof("truncate the unstable entries before index %d", after)
|
|
u.entries = append([]pb.Entry{}, u.slice(u.offset, after)...)
|
|
u.entries = append(u.entries, ents...)
|
|
}
|
|
}
|
|
|
|
func (u *unstable) slice(lo uint64, hi uint64) []pb.Entry {
|
|
u.mustCheckOutOfBounds(lo, hi)
|
|
return u.entries[lo-u.offset : hi-u.offset]
|
|
}
|
|
|
|
// u.offset <= lo <= hi <= u.offset+len(u.entries)
|
|
func (u *unstable) mustCheckOutOfBounds(lo, hi uint64) {
|
|
if lo > hi {
|
|
u.logger.Panicf("invalid unstable.slice %d > %d", lo, hi)
|
|
}
|
|
upper := u.offset + uint64(len(u.entries))
|
|
if lo < u.offset || hi > upper {
|
|
u.logger.Panicf("unstable.slice[%d,%d) out of bound [%d,%d]", lo, hi, u.offset, upper)
|
|
}
|
|
}
|