fix #285. fixing some problems with req num roll over
parent
0fd2a4c267
commit
df2056de8a
|
@ -26,21 +26,17 @@ func (self *index) addEntry(startRequestNumber, size uint32, currentOffset uint6
|
||||||
self.CurrentOffset = currentOffset
|
self.CurrentOffset = currentOffset
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *index) findOffsetBlock(requestNumber uint32) func(int) bool {
|
func (self *index) findOffsetBlock(order RequestNumberOrder, requestNumber uint32) func(int) bool {
|
||||||
return func(i int) bool {
|
return func(i int) bool {
|
||||||
// The returned function must satisfy `f(i) => f(i+1)`, meaning if
|
// The returned function must satisfy `f(i) => f(i+1)`, meaning if
|
||||||
// for index i f returns true, then it must return true for every
|
// for index i f returns true, then it must return true for every
|
||||||
// index greater than i. sort.Search will return the smallest
|
// index greater than i. sort.Search will return the smallest
|
||||||
// index satisfying f
|
// index satisfying f
|
||||||
if self.Entries[i].StartRequestNumber > requestNumber {
|
return order.isAfter(self.Entries[i].StartRequestNumber, requestNumber)
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *index) requestOffset(requestNumber uint32) uint64 {
|
func (self *index) requestOffset(order RequestNumberOrder, requestNumber uint32) uint64 {
|
||||||
numberOfEntries := len(self.Entries)
|
numberOfEntries := len(self.Entries)
|
||||||
if numberOfEntries == 0 {
|
if numberOfEntries == 0 {
|
||||||
logger.Info("no index entries, assuming beginning of the file")
|
logger.Info("no index entries, assuming beginning of the file")
|
||||||
|
@ -48,15 +44,15 @@ func (self *index) requestOffset(requestNumber uint32) uint64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
firstEntry := self.Entries[0]
|
firstEntry := self.Entries[0]
|
||||||
if requestNumber < firstEntry.StartRequestNumber {
|
if order.isBeforeOrEqual(requestNumber, firstEntry.StartRequestNumber) {
|
||||||
return firstEntry.StartOffset
|
return firstEntry.StartOffset
|
||||||
}
|
}
|
||||||
|
|
||||||
lastEntry := self.Entries[numberOfEntries-1]
|
lastEntry := self.Entries[numberOfEntries-1]
|
||||||
if requestNumber >= lastEntry.StartRequestNumber {
|
if order.isAfterOrEqual(requestNumber, lastEntry.StartRequestNumber) {
|
||||||
return lastEntry.StartOffset
|
return lastEntry.StartOffset
|
||||||
}
|
}
|
||||||
|
|
||||||
index := sort.Search(numberOfEntries, self.findOffsetBlock(requestNumber))
|
index := sort.Search(numberOfEntries, self.findOffsetBlock(order, requestNumber))
|
||||||
return self.Entries[index-1].StartOffset
|
return self.Entries[index-1].StartOffset
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,6 +104,7 @@ func (self *log) recover() error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
defer bookmark.Close()
|
||||||
if err := self.state.read(bookmark); err != nil {
|
if err := self.state.read(bookmark); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -123,7 +124,7 @@ func (self *log) recover() error {
|
||||||
stopChan := make(chan struct{})
|
stopChan := make(chan struct{})
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
self.replayFromFileLocation(self.file, map[uint32]struct{}{}, 0, replayChan, stopChan)
|
self.replayFromFileLocation(self.file, map[uint32]struct{}{}, replayChan, stopChan)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
|
@ -230,7 +231,7 @@ func (self *log) dupLogFile() (*os.File, error) {
|
||||||
|
|
||||||
// replay requests starting at the given requestNumber and for the
|
// replay requests starting at the given requestNumber and for the
|
||||||
// given shard ids. Return all requests if shardIds is empty
|
// given shard ids. Return all requests if shardIds is empty
|
||||||
func (self *log) replayFromRequestNumber(shardIds []uint32, requestNumber uint32) (chan *replayRequest, chan struct{}) {
|
func (self *log) replayFromRequestNumber(shardIds []uint32, requestNumber uint32, order RequestNumberOrder) (chan *replayRequest, chan struct{}) {
|
||||||
// this channel needs to be buffered in case the last request in the
|
// this channel needs to be buffered in case the last request in the
|
||||||
// log file caused an error in the yield function
|
// log file caused an error in the yield function
|
||||||
stopChan := make(chan struct{}, 1)
|
stopChan := make(chan struct{}, 1)
|
||||||
|
@ -244,7 +245,7 @@ func (self *log) replayFromRequestNumber(shardIds []uint32, requestNumber uint32
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
offset := self.state.Index.requestOffset(requestNumber)
|
offset := self.state.Index.requestOffset(order, requestNumber)
|
||||||
logger.Debug("Replaying from file offset %d", offset)
|
logger.Debug("Replaying from file offset %d", offset)
|
||||||
_, err = file.Seek(int64(offset), os.SEEK_SET)
|
_, err = file.Seek(int64(offset), os.SEEK_SET)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -256,24 +257,61 @@ func (self *log) replayFromRequestNumber(shardIds []uint32, requestNumber uint32
|
||||||
for _, shardId := range shardIds {
|
for _, shardId := range shardIds {
|
||||||
shardIdsSet[shardId] = struct{}{}
|
shardIdsSet[shardId] = struct{}{}
|
||||||
}
|
}
|
||||||
self.replayFromFileLocation(file, shardIdsSet, requestNumber, replayChan, stopChan)
|
if err := self.skipToRequest(file, requestNumber, order); err != nil {
|
||||||
|
sendOrStop(newErrorReplayRequest(err), replayChan, stopChan)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.replayFromFileLocation(file, shardIdsSet, replayChan, stopChan)
|
||||||
}()
|
}()
|
||||||
return replayChan, stopChan
|
return replayChan, stopChan
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *log) getNextHeader(file *os.File) (int, *entryHeader, error) {
|
||||||
|
hdr := &entryHeader{}
|
||||||
|
numberOfBytes, err := hdr.Read(file)
|
||||||
|
if err == io.EOF {
|
||||||
|
return 0, nil, nil
|
||||||
|
}
|
||||||
|
return numberOfBytes, hdr, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *log) skipRequest(file *os.File, hdr *entryHeader) (err error) {
|
||||||
|
_, err = file.Seek(int64(hdr.length), os.SEEK_CUR)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *log) skipToRequest(file *os.File, requestNumber uint32, order RequestNumberOrder) error {
|
||||||
|
for {
|
||||||
|
n, hdr, err := self.getNextHeader(file)
|
||||||
|
if n == 0 {
|
||||||
|
// EOF
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if order.isBefore(hdr.requestNumber, requestNumber) {
|
||||||
|
if err := self.skipRequest(file, hdr); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// seek back to the beginning of the request header
|
||||||
|
_, err = file.Seek(int64(-n), os.SEEK_CUR)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (self *log) replayFromFileLocation(file *os.File,
|
func (self *log) replayFromFileLocation(file *os.File,
|
||||||
shardIdsSet map[uint32]struct{},
|
shardIdsSet map[uint32]struct{},
|
||||||
requestNumber uint32,
|
|
||||||
replayChan chan *replayRequest,
|
replayChan chan *replayRequest,
|
||||||
stopChan chan struct{}) {
|
stopChan chan struct{}) {
|
||||||
|
|
||||||
defer func() { close(replayChan) }()
|
defer func() { close(replayChan) }()
|
||||||
for {
|
for {
|
||||||
hdr := &entryHeader{}
|
numberOfBytes, hdr, err := self.getNextHeader(file)
|
||||||
numberOfBytes, err := hdr.Read(file)
|
if numberOfBytes == 0 {
|
||||||
|
break
|
||||||
if err == io.EOF {
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -288,8 +326,8 @@ func (self *log) replayFromFileLocation(file *os.File,
|
||||||
} else {
|
} else {
|
||||||
_, ok = shardIdsSet[hdr.shardId]
|
_, ok = shardIdsSet[hdr.shardId]
|
||||||
}
|
}
|
||||||
if !ok || hdr.requestNumber < requestNumber {
|
if !ok {
|
||||||
_, err = file.Seek(int64(hdr.length), os.SEEK_CUR)
|
err = self.skipRequest(file, hdr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sendOrStop(newErrorReplayRequest(err), replayChan, stopChan)
|
sendOrStop(newErrorReplayRequest(err), replayChan, stopChan)
|
||||||
return
|
return
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
package wal
|
||||||
|
|
||||||
|
type RequestNumberOrder interface {
|
||||||
|
isAfter(uint32, uint32) bool
|
||||||
|
isAfterOrEqual(uint32, uint32) bool
|
||||||
|
isBefore(uint32, uint32) bool
|
||||||
|
isBeforeOrEqual(uint32, uint32) bool
|
||||||
|
}
|
|
@ -1,15 +1,20 @@
|
||||||
package wal
|
package wal
|
||||||
|
|
||||||
type sortableLogSlice []*log
|
type sortableLogSlice struct {
|
||||||
|
logFiles []*log
|
||||||
|
order RequestNumberOrder
|
||||||
|
}
|
||||||
|
|
||||||
func (self sortableLogSlice) Len() int {
|
func (self sortableLogSlice) Len() int {
|
||||||
return len(self)
|
return len(self.logFiles)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self sortableLogSlice) Less(i, j int) bool {
|
func (self sortableLogSlice) Less(i, j int) bool {
|
||||||
return self[i].firstRequestNumber() < self[j].firstRequestNumber()
|
left := self.logFiles[i].firstRequestNumber()
|
||||||
|
right := self.logFiles[j].firstRequestNumber()
|
||||||
|
return self.order.isBefore(left, right)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self sortableLogSlice) Swap(i, j int) {
|
func (self sortableLogSlice) Swap(i, j int) {
|
||||||
self[i], self[j] = self[j], self[i]
|
self.logFiles[i], self.logFiles[j] = self.logFiles[j], self.logFiles[i]
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,11 +21,37 @@ type state struct {
|
||||||
FileOffset int64 // the file offset at which this bookmark was created
|
FileOffset int64 // the file offset at which this bookmark was created
|
||||||
Index *index
|
Index *index
|
||||||
TotalNumberOfRequests int
|
TotalNumberOfRequests int
|
||||||
|
FirstRequestNumber uint32
|
||||||
LargestRequestNumber uint32
|
LargestRequestNumber uint32
|
||||||
ShardLastSequenceNumber map[uint32]uint64
|
ShardLastSequenceNumber map[uint32]uint64
|
||||||
ServerLastRequestNumber map[uint32]uint32
|
ServerLastRequestNumber map[uint32]uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *state) isAfter(left, right uint32) bool {
|
||||||
|
if left == right {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if left >= self.FirstRequestNumber && right >= self.FirstRequestNumber {
|
||||||
|
return left > right
|
||||||
|
}
|
||||||
|
if left <= self.LargestRequestNumber && right <= self.LargestRequestNumber {
|
||||||
|
return left > right
|
||||||
|
}
|
||||||
|
return left <= self.LargestRequestNumber
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *state) isAfterOrEqual(left, right uint32) bool {
|
||||||
|
return left == right || self.isAfter(left, right)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *state) isBefore(left, right uint32) bool {
|
||||||
|
return !self.isAfterOrEqual(left, right)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *state) isBeforeOrEqual(left, right uint32) bool {
|
||||||
|
return !self.isAfter(left, right)
|
||||||
|
}
|
||||||
|
|
||||||
func newState() *state {
|
func newState() *state {
|
||||||
return &state{
|
return &state{
|
||||||
Version: CURRENT_VERSION,
|
Version: CURRENT_VERSION,
|
||||||
|
@ -64,6 +90,7 @@ func (self *state) getNextRequestNumber() uint32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *state) continueFromState(state *state) {
|
func (self *state) continueFromState(state *state) {
|
||||||
|
self.FirstRequestNumber = state.FirstRequestNumber
|
||||||
self.LargestRequestNumber = state.LargestRequestNumber
|
self.LargestRequestNumber = state.LargestRequestNumber
|
||||||
self.ShardLastSequenceNumber = state.ShardLastSequenceNumber
|
self.ShardLastSequenceNumber = state.ShardLastSequenceNumber
|
||||||
self.ServerLastRequestNumber = state.ServerLastRequestNumber
|
self.ServerLastRequestNumber = state.ServerLastRequestNumber
|
||||||
|
|
|
@ -66,8 +66,6 @@ func NewWAL(config *configuration.Configuration) (*WAL, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// sort the logfiles by the first request number in the log
|
// sort the logfiles by the first request number in the log
|
||||||
sort.Sort(sortableLogSlice(logFiles))
|
|
||||||
|
|
||||||
wal := &WAL{
|
wal := &WAL{
|
||||||
config: config,
|
config: config,
|
||||||
logFiles: logFiles,
|
logFiles: logFiles,
|
||||||
|
@ -79,6 +77,9 @@ func NewWAL(config *configuration.Configuration) (*WAL, error) {
|
||||||
// if we don't have any log files open yet, open a new one
|
// if we don't have any log files open yet, open a new one
|
||||||
if len(logFiles) == 0 {
|
if len(logFiles) == 0 {
|
||||||
_, err = wal.createNewLog()
|
_, err = wal.createNewLog()
|
||||||
|
} else {
|
||||||
|
state := logFiles[len(logFiles)-1].state
|
||||||
|
sort.Sort(sortableLogSlice{logFiles, state})
|
||||||
}
|
}
|
||||||
|
|
||||||
go wal.processEntries()
|
go wal.processEntries()
|
||||||
|
@ -113,11 +114,12 @@ func (self *WAL) RecoverServerFromLastCommit(serverId uint32, shardIds []uint32,
|
||||||
func (self *WAL) RecoverServerFromRequestNumber(requestNumber uint32, shardIds []uint32, yield func(request *protocol.Request, shardId uint32) error) error {
|
func (self *WAL) RecoverServerFromRequestNumber(requestNumber uint32, shardIds []uint32, yield func(request *protocol.Request, shardId uint32) error) error {
|
||||||
var firstLogFile int
|
var firstLogFile int
|
||||||
|
|
||||||
|
state := self.logFiles[len(self.logFiles)-1].state
|
||||||
outer:
|
outer:
|
||||||
for _, logFile := range self.logFiles[firstLogFile:] {
|
for _, logFile := range self.logFiles[firstLogFile:] {
|
||||||
logger.Info("Replaying from %s", logFile.file.Name())
|
logger.Info("Replaying from %s", logFile.file.Name())
|
||||||
count := 0
|
count := 0
|
||||||
ch, stopChan := logFile.replayFromRequestNumber(shardIds, requestNumber)
|
ch, stopChan := logFile.replayFromRequestNumber(shardIds, requestNumber, state)
|
||||||
for {
|
for {
|
||||||
x := <-ch
|
x := <-ch
|
||||||
if x == nil {
|
if x == nil {
|
||||||
|
@ -210,6 +212,7 @@ func (self *WAL) processCommitEntry(e *commitEntry) {
|
||||||
logFile.close()
|
logFile.close()
|
||||||
logFile.delete()
|
logFile.delete()
|
||||||
}
|
}
|
||||||
|
lastLogFile.state.FirstRequestNumber = self.logFiles[0].firstRequestNumber()
|
||||||
e.confirmation <- &confirmation{0, nil}
|
e.confirmation <- &confirmation{0, nil}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,9 +253,9 @@ func (self *WAL) AssignSequenceNumbersAndLog(request *protocol.Request, shard Sh
|
||||||
return confirmation.requestNumber, confirmation.err
|
return confirmation.requestNumber, confirmation.err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *WAL) doesLogFileContainRequest(requestNumber uint32) func(int) bool {
|
func (self *WAL) doesLogFileContainRequest(order RequestNumberOrder, requestNumber uint32) func(int) bool {
|
||||||
return func(i int) bool {
|
return func(i int) bool {
|
||||||
if self.logFiles[i].firstRequestNumber() > requestNumber {
|
if order.isAfter(self.logFiles[i].firstRequestNumber(), requestNumber) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
@ -262,12 +265,16 @@ func (self *WAL) doesLogFileContainRequest(requestNumber uint32) func(int) bool
|
||||||
// returns the first log file that contains the given request number
|
// returns the first log file that contains the given request number
|
||||||
func (self *WAL) firstLogFile(requestNumber uint32) int {
|
func (self *WAL) firstLogFile(requestNumber uint32) int {
|
||||||
lengthLogFiles := len(self.logFiles)
|
lengthLogFiles := len(self.logFiles)
|
||||||
if requestNumber >= self.logFiles[lengthLogFiles-1].firstRequestNumber() {
|
|
||||||
|
lastLogFile := self.logFiles[len(self.logFiles)-1]
|
||||||
|
state := lastLogFile.state
|
||||||
|
|
||||||
|
if state.isAfterOrEqual(requestNumber, lastLogFile.firstRequestNumber()) {
|
||||||
return lengthLogFiles - 1
|
return lengthLogFiles - 1
|
||||||
} else if requestNumber <= self.logFiles[0].firstRequestNumber() {
|
} else if state.isAfterOrEqual(self.logFiles[0].firstRequestNumber(), requestNumber) {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
return sort.Search(lengthLogFiles, self.doesLogFileContainRequest(requestNumber)) - 1
|
return sort.Search(lengthLogFiles, self.doesLogFileContainRequest(state, requestNumber)) - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *WAL) shouldRotateTheLogFile() bool {
|
func (self *WAL) shouldRotateTheLogFile() bool {
|
||||||
|
@ -281,6 +288,7 @@ func (self *WAL) rotateTheLogFile() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
lastLogFile := self.logFiles[len(self.logFiles)-1]
|
lastLogFile := self.logFiles[len(self.logFiles)-1]
|
||||||
|
lastLogFile.state.FirstRequestNumber = self.logFiles[0].firstRequestNumber()
|
||||||
err := lastLogFile.forceBookmark()
|
err := lastLogFile.forceBookmark()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"configuration"
|
"configuration"
|
||||||
"fmt"
|
"fmt"
|
||||||
. "launchpad.net/gocheck"
|
. "launchpad.net/gocheck"
|
||||||
|
"math"
|
||||||
"net/http"
|
"net/http"
|
||||||
_ "net/http/pprof"
|
_ "net/http/pprof"
|
||||||
"os"
|
"os"
|
||||||
|
@ -253,6 +254,76 @@ func (_ *WalSuite) TestReplay(c *C) {
|
||||||
c.Assert(err, IsNil)
|
c.Assert(err, IsNil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: test roll over with multiple log files (this will test
|
||||||
|
// sorting of the log files)
|
||||||
|
func (_ *WalSuite) TestRequestNumberRollOver(c *C) {
|
||||||
|
wal := newWal(c)
|
||||||
|
firstRequestNumber := uint32(math.MaxUint32 - 10)
|
||||||
|
wal.logFiles[0].state.LargestRequestNumber = firstRequestNumber
|
||||||
|
var i uint32
|
||||||
|
for i = 0; i < 20; i++ {
|
||||||
|
req := generateRequest(2)
|
||||||
|
n, err := wal.AssignSequenceNumbersAndLog(req, &MockShard{id: 1})
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
c.Assert(n, Equals, firstRequestNumber+i+1)
|
||||||
|
}
|
||||||
|
wal.Close()
|
||||||
|
requests := []*protocol.Request{}
|
||||||
|
wal.RecoverServerFromRequestNumber(firstRequestNumber, []uint32{1}, func(req *protocol.Request, shardId uint32) error {
|
||||||
|
requests = append(requests, req)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
c.Assert(requests, HasLen, 20)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_ *WalSuite) TestRequestNumberRollOverAcrossMultipleFiles(c *C) {
|
||||||
|
wal := newWal(c)
|
||||||
|
firstRequestNumber := uint32(math.MaxUint32 - 5000)
|
||||||
|
wal.logFiles[0].state.LargestRequestNumber = firstRequestNumber
|
||||||
|
var i uint32
|
||||||
|
for i = 0; i < 20000; i++ {
|
||||||
|
req := generateRequest(2)
|
||||||
|
n, err := wal.AssignSequenceNumbersAndLog(req, &MockShard{id: 1})
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
c.Assert(n, Equals, firstRequestNumber+i+1)
|
||||||
|
}
|
||||||
|
wal.Close()
|
||||||
|
requests := []*protocol.Request{}
|
||||||
|
wal.RecoverServerFromRequestNumber(firstRequestNumber, []uint32{1}, func(req *protocol.Request, shardId uint32) error {
|
||||||
|
requests = append(requests, req)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
c.Assert(len(requests), Equals, 20000)
|
||||||
|
wal, err := NewWAL(wal.config)
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
requests = []*protocol.Request{}
|
||||||
|
wal.RecoverServerFromRequestNumber(firstRequestNumber, []uint32{1}, func(req *protocol.Request, shardId uint32) error {
|
||||||
|
requests = append(requests, req)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
c.Assert(len(requests), Equals, 20000)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_ *WalSuite) TestRequestNumberRollOverAndIndexing(c *C) {
|
||||||
|
wal := newWal(c)
|
||||||
|
firstRequestNumber := uint32(math.MaxUint32 - 5000)
|
||||||
|
wal.logFiles[0].state.LargestRequestNumber = firstRequestNumber
|
||||||
|
var i uint32
|
||||||
|
for i = 0; i < 20000; i++ {
|
||||||
|
req := generateRequest(2)
|
||||||
|
n, err := wal.AssignSequenceNumbersAndLog(req, &MockShard{id: 1})
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
c.Assert(n, Equals, firstRequestNumber+i+1)
|
||||||
|
}
|
||||||
|
wal.Close()
|
||||||
|
requests := []*protocol.Request{}
|
||||||
|
wal.RecoverServerFromRequestNumber(0, []uint32{1}, func(req *protocol.Request, shardId uint32) error {
|
||||||
|
requests = append(requests, req)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
c.Assert(len(requests), Equals, 15000)
|
||||||
|
}
|
||||||
|
|
||||||
func (_ *WalSuite) TestRecoveryFromCrash(c *C) {
|
func (_ *WalSuite) TestRecoveryFromCrash(c *C) {
|
||||||
wal := newWal(c)
|
wal := newWal(c)
|
||||||
req := generateRequest(2)
|
req := generateRequest(2)
|
||||||
|
@ -376,10 +447,11 @@ func (_ *WalSuite) TestIndex(c *C) {
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Assert(wal.logFiles[0].state.Index.Entries, HasLen, 3)
|
c.Assert(wal.logFiles[0].state.Index.Entries, HasLen, 3)
|
||||||
requestOffset := wal.logFiles[0].state.Index.requestOffset(2001)
|
state := wal.logFiles[len(wal.logFiles)-1].state
|
||||||
|
requestOffset := wal.logFiles[0].state.Index.requestOffset(state, 2001)
|
||||||
c.Assert(requestOffset > 0, Equals, true)
|
c.Assert(requestOffset > 0, Equals, true)
|
||||||
// request 2000 should be in the second block not the third block
|
// request 2000 should be in the second block not the third block
|
||||||
c.Assert(requestOffset > wal.logFiles[0].state.Index.requestOffset(2000), Equals, true)
|
c.Assert(requestOffset > wal.logFiles[0].state.Index.requestOffset(state, 2000), Equals, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (_ *WalSuite) TestSequenceNumberAssignment(c *C) {
|
func (_ *WalSuite) TestSequenceNumberAssignment(c *C) {
|
||||||
|
|
Loading…
Reference in New Issue