add page chunk interval list

This commit is contained in:
chrislu 2021-12-22 02:53:33 -08:00
parent b7cd52636b
commit 7b78fc72b0
2 changed files with 145 additions and 0 deletions

View file

@ -0,0 +1,96 @@
package page_writer
import "math"
// PageChunkWrittenInterval mark one written interval within one page chunk
type PageChunkWrittenInterval struct {
startOffset int64
stopOffset int64
prev *PageChunkWrittenInterval
next *PageChunkWrittenInterval
}
// PageChunkWrittenIntervalList mark written intervals within one page chunk
type PageChunkWrittenIntervalList struct {
head *PageChunkWrittenInterval
tail *PageChunkWrittenInterval
}
func newPageChunkWrittenIntervalList() *PageChunkWrittenIntervalList {
list := &PageChunkWrittenIntervalList{
head: &PageChunkWrittenInterval{
startOffset: -1,
stopOffset: -1,
},
tail: &PageChunkWrittenInterval{
startOffset: math.MaxInt64,
stopOffset: math.MaxInt64,
},
}
list.head.next = list.tail
list.tail.prev = list.head
return list
}
func (list *PageChunkWrittenIntervalList) MarkWritten(startOffset, stopOffset int64) {
interval := &PageChunkWrittenInterval{
startOffset: startOffset,
stopOffset: stopOffset,
}
list.addInterval(interval)
}
func (list *PageChunkWrittenIntervalList) addInterval(interval *PageChunkWrittenInterval) {
p := list.head
for ; p.next != nil && p.next.startOffset <= interval.startOffset; p = p.next {
}
q := list.tail
for ; q.prev != nil && q.prev.stopOffset >= interval.stopOffset; q = q.prev {
}
if interval.startOffset <= p.stopOffset && q.startOffset <= interval.stopOffset {
// merge p and q together
p.stopOffset = q.stopOffset
unlinkNodesBetween(p, q.next)
return
}
if interval.startOffset <= p.stopOffset {
// merge new interval into p
p.stopOffset = interval.stopOffset
unlinkNodesBetween(p, q)
return
}
if q.startOffset <= interval.stopOffset {
// merge new interval into q
q.startOffset = interval.startOffset
unlinkNodesBetween(p, q)
return
}
// add the new interval between p and q
unlinkNodesBetween(p, q)
p.next = interval
interval.prev = p
q.prev = interval
interval.next = q
}
// unlinkNodesBetween remove all nodes after start and before stop, exclusive
func unlinkNodesBetween(start *PageChunkWrittenInterval, stop *PageChunkWrittenInterval) {
if start.next == stop {
return
}
start.next.prev = nil
start.next = stop
stop.prev.next = nil
stop.prev = start
}
func (list *PageChunkWrittenIntervalList) size() int {
var count int
for t := list.head; t != nil; t = t.next {
count++
}
return count - 2
}

View file

@ -0,0 +1,49 @@
package page_writer
import (
"github.com/stretchr/testify/assert"
"testing"
)
func Test_PageChunkWrittenIntervalList(t *testing.T) {
list := newPageChunkWrittenIntervalList()
assert.Equal(t, 0, list.size(), "empty list")
list.MarkWritten(0, 5)
assert.Equal(t, 1, list.size(), "one interval")
list.MarkWritten(0, 5)
assert.Equal(t, 1, list.size(), "duplicated interval2")
list.MarkWritten(95, 100)
assert.Equal(t, 2, list.size(), "two intervals")
list.MarkWritten(50, 60)
assert.Equal(t, 3, list.size(), "three intervals")
list.MarkWritten(50, 55)
assert.Equal(t, 3, list.size(), "three intervals merge")
list.MarkWritten(40, 50)
assert.Equal(t, 3, list.size(), "three intervals grow forward")
list.MarkWritten(50, 65)
assert.Equal(t, 3, list.size(), "three intervals grow backward")
list.MarkWritten(70, 80)
assert.Equal(t, 4, list.size(), "four intervals")
list.MarkWritten(60, 70)
assert.Equal(t, 3, list.size(), "three intervals merged")
list.MarkWritten(59, 71)
assert.Equal(t, 3, list.size(), "covered three intervals")
list.MarkWritten(5, 59)
assert.Equal(t, 2, list.size(), "covered two intervals")
list.MarkWritten(70, 99)
assert.Equal(t, 1, list.size(), "covered one intervals")
}