You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							220 lines
						
					
					
						
							6.0 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							220 lines
						
					
					
						
							6.0 KiB
						
					
					
				| 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...) | |
| }
 |