123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220 |
- package filesys
- import (
- "bytes"
- "io"
- "math"
- )
- type IntervalNode struct {
- Data []byte
- Offset int64
- Size int64
- Next *IntervalNode
- }
- type IntervalLinkedList struct {
- Head *IntervalNode
- Tail *IntervalNode
- }
- type ContinuousIntervals struct {
- lists []*IntervalLinkedList
- }
- func (list *IntervalLinkedList) Offset() int64 {
- return list.Head.Offset
- }
- func (list *IntervalLinkedList) Size() int64 {
- return list.Tail.Offset + list.Tail.Size - list.Head.Offset
- }
- func (list *IntervalLinkedList) addNodeToTail(node *IntervalNode) {
- // glog.V(4).Infof("add to tail [%d,%d) + [%d,%d) => [%d,%d)", list.Head.Offset, list.Tail.Offset+list.Tail.Size, node.Offset, node.Offset+node.Size, list.Head.Offset, node.Offset+node.Size)
- list.Tail.Next = node
- list.Tail = node
- }
- func (list *IntervalLinkedList) addNodeToHead(node *IntervalNode) {
- // glog.V(4).Infof("add to head [%d,%d) + [%d,%d) => [%d,%d)", node.Offset, node.Offset+node.Size, list.Head.Offset, list.Tail.Offset+list.Tail.Size, node.Offset, list.Tail.Offset+list.Tail.Size)
- node.Next = list.Head
- list.Head = node
- }
- func (list *IntervalLinkedList) ReadData(buf []byte, start, stop int64) {
- t := list.Head
- for {
- nodeStart, nodeStop := max(start, t.Offset), min(stop, t.Offset+t.Size)
- if nodeStart < nodeStop {
- // glog.V(0).Infof("copying start=%d stop=%d t=[%d,%d) t.data=%d => bufSize=%d nodeStart=%d, nodeStop=%d", start, stop, t.Offset, t.Offset+t.Size, len(t.Data), len(buf), nodeStart, nodeStop)
- copy(buf[nodeStart-start:], t.Data[nodeStart-t.Offset:nodeStop-t.Offset])
- }
- if t.Next == nil {
- break
- }
- t = t.Next
- }
- }
- func (c *ContinuousIntervals) TotalSize() (total int64) {
- for _, list := range c.lists {
- total += list.Size()
- }
- return
- }
- func subList(list *IntervalLinkedList, start, stop int64) *IntervalLinkedList {
- var nodes []*IntervalNode
- for t := list.Head; t != nil; t = t.Next {
- nodeStart, nodeStop := max(start, t.Offset), min(stop, t.Offset+t.Size)
- if nodeStart >= nodeStop {
- // skip non overlapping IntervalNode
- continue
- }
- nodes = append(nodes, &IntervalNode{
- Data: t.Data[nodeStart-t.Offset : nodeStop-t.Offset],
- Offset: nodeStart,
- Size: nodeStop - nodeStart,
- Next: nil,
- })
- }
- for i := 1; i < len(nodes); i++ {
- nodes[i-1].Next = nodes[i]
- }
- return &IntervalLinkedList{
- Head: nodes[0],
- Tail: nodes[len(nodes)-1],
- }
- }
- func (c *ContinuousIntervals) AddInterval(data []byte, offset int64) {
- interval := &IntervalNode{Data: data, Offset: offset, Size: int64(len(data))}
- var newLists []*IntervalLinkedList
- for _, list := range c.lists {
- // if list is to the left of new interval, add to the new list
- if list.Tail.Offset+list.Tail.Size <= interval.Offset {
- newLists = append(newLists, list)
- }
- // if list is to the right of new interval, add to the new list
- if interval.Offset+interval.Size <= list.Head.Offset {
- newLists = append(newLists, list)
- }
- // if new interval overwrite the right part of the list
- if list.Head.Offset < interval.Offset && interval.Offset < list.Tail.Offset+list.Tail.Size {
- // create a new list of the left part of existing list
- newLists = append(newLists, subList(list, list.Offset(), interval.Offset))
- }
- // if new interval overwrite the left part of the list
- if list.Head.Offset < interval.Offset+interval.Size && interval.Offset+interval.Size < list.Tail.Offset+list.Tail.Size {
- // create a new list of the right part of existing list
- newLists = append(newLists, subList(list, interval.Offset+interval.Size, list.Tail.Offset+list.Tail.Size))
- }
- // skip anything that is fully overwritten by the new interval
- }
- c.lists = newLists
- // add the new interval to the lists, connecting neighbor lists
- var prevList, nextList *IntervalLinkedList
- for _, list := range c.lists {
- if list.Head.Offset == interval.Offset+interval.Size {
- nextList = list
- break
- }
- }
- for _, list := range c.lists {
- if list.Head.Offset+list.Size() == offset {
- list.addNodeToTail(interval)
- prevList = list
- break
- }
- }
- if prevList != nil && nextList != nil {
- // glog.V(4).Infof("connecting [%d,%d) + [%d,%d) => [%d,%d)", prevList.Head.Offset, prevList.Tail.Offset+prevList.Tail.Size, nextList.Head.Offset, nextList.Tail.Offset+nextList.Tail.Size, prevList.Head.Offset, nextList.Tail.Offset+nextList.Tail.Size)
- prevList.Tail.Next = nextList.Head
- prevList.Tail = nextList.Tail
- c.removeList(nextList)
- } else if nextList != nil {
- // add to head was not done when checking
- nextList.addNodeToHead(interval)
- }
- if prevList == nil && nextList == nil {
- c.lists = append(c.lists, &IntervalLinkedList{
- Head: interval,
- Tail: interval,
- })
- }
- return
- }
- func (c *ContinuousIntervals) RemoveLargestIntervalLinkedList() *IntervalLinkedList {
- var maxSize int64
- maxIndex := -1
- for k, list := range c.lists {
- if maxSize <= list.Size() {
- maxSize = list.Size()
- maxIndex = k
- }
- }
- if maxSize <= 0 {
- return nil
- }
- t := c.lists[maxIndex]
- c.lists = append(c.lists[0:maxIndex], c.lists[maxIndex+1:]...)
- return t
- }
- func (c *ContinuousIntervals) removeList(target *IntervalLinkedList) {
- index := -1
- for k, list := range c.lists {
- if list.Offset() == target.Offset() {
- index = k
- }
- }
- if index < 0 {
- return
- }
- c.lists = append(c.lists[0:index], c.lists[index+1:]...)
- }
- func (c *ContinuousIntervals) ReadData(data []byte, startOffset int64) (offset int64, size int) {
- var minOffset int64 = math.MaxInt64
- var maxStop int64
- for _, list := range c.lists {
- start := max(startOffset, list.Offset())
- stop := min(startOffset+int64(len(data)), list.Offset()+list.Size())
- if start <= stop {
- list.ReadData(data[start-startOffset:], start, stop)
- minOffset = min(minOffset, start)
- maxStop = max(maxStop, stop)
- }
- }
- if minOffset == math.MaxInt64 {
- return 0, 0
- }
- offset = minOffset
- size = int(maxStop - offset)
- return
- }
- func (l *IntervalLinkedList) ToReader() io.Reader {
- var readers []io.Reader
- t := l.Head
- readers = append(readers, bytes.NewReader(t.Data))
- for t.Next != nil {
- t = t.Next
- readers = append(readers, bytes.NewReader(t.Data))
- }
- return io.MultiReader(readers...)
- }
|