chrislu
3 years ago
2 changed files with 145 additions and 0 deletions
-
96weed/filesys/page_writer/page_chunk_interval_list.go
-
49weed/filesys/page_writer/page_chunk_interval_list_test.go
@ -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 |
||||
|
} |
@ -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") |
||||
|
|
||||
|
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue