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.
		
		
		
		
		
			
		
			
				
					
					
						
							259 lines
						
					
					
						
							5.7 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							259 lines
						
					
					
						
							5.7 KiB
						
					
					
				| package filer | |
| 
 | |
| import ( | |
| 	"math" | |
| 	"sync" | |
| ) | |
| 
 | |
| type IntervalValue interface { | |
| 	SetStartStop(start, stop int64) | |
| 	Clone() IntervalValue | |
| } | |
| 
 | |
| type Interval[T IntervalValue] struct { | |
| 	StartOffset int64 | |
| 	StopOffset  int64 | |
| 	TsNs        int64 | |
| 	Value       T | |
| 	Prev        *Interval[T] | |
| 	Next        *Interval[T] | |
| } | |
| 
 | |
| func (interval *Interval[T]) Size() int64 { | |
| 	return interval.StopOffset - interval.StartOffset | |
| } | |
| 
 | |
| // IntervalList mark written intervals within one page chunk | |
| type IntervalList[T IntervalValue] struct { | |
| 	head *Interval[T] | |
| 	tail *Interval[T] | |
| 	Lock sync.RWMutex | |
| } | |
| 
 | |
| func NewIntervalList[T IntervalValue]() *IntervalList[T] { | |
| 	list := &IntervalList[T]{ | |
| 		head: &Interval[T]{ | |
| 			StartOffset: -1, | |
| 			StopOffset:  -1, | |
| 		}, | |
| 		tail: &Interval[T]{ | |
| 			StartOffset: math.MaxInt64, | |
| 			StopOffset:  math.MaxInt64, | |
| 		}, | |
| 	} | |
| 	return list | |
| } | |
| 
 | |
| func (list *IntervalList[T]) Front() (interval *Interval[T]) { | |
| 	return list.head.Next | |
| } | |
| 
 | |
| func (list *IntervalList[T]) AppendInterval(interval *Interval[T]) { | |
| 	list.Lock.Lock() | |
| 	defer list.Lock.Unlock() | |
| 
 | |
| 	if list.head.Next == nil { | |
| 		list.head.Next = interval | |
| 	} | |
| 	interval.Prev = list.tail.Prev | |
| 	if list.tail.Prev != nil { | |
| 		list.tail.Prev.Next = interval | |
| 	} | |
| 	list.tail.Prev = interval | |
| } | |
| 
 | |
| func (list *IntervalList[T]) Overlay(startOffset, stopOffset, tsNs int64, value T) { | |
| 	if startOffset >= stopOffset { | |
| 		return | |
| 	} | |
| 	interval := &Interval[T]{ | |
| 		StartOffset: startOffset, | |
| 		StopOffset:  stopOffset, | |
| 		TsNs:        tsNs, | |
| 		Value:       value, | |
| 	} | |
| 
 | |
| 	list.Lock.Lock() | |
| 	defer list.Lock.Unlock() | |
| 
 | |
| 	list.overlayInterval(interval) | |
| } | |
| 
 | |
| func (list *IntervalList[T]) InsertInterval(startOffset, stopOffset, tsNs int64, value T) { | |
| 	interval := &Interval[T]{ | |
| 		StartOffset: startOffset, | |
| 		StopOffset:  stopOffset, | |
| 		TsNs:        tsNs, | |
| 		Value:       value, | |
| 	} | |
| 
 | |
| 	list.Lock.Lock() | |
| 	defer list.Lock.Unlock() | |
| 
 | |
| 	value.SetStartStop(startOffset, stopOffset) | |
| 	list.insertInterval(interval) | |
| } | |
| 
 | |
| func (list *IntervalList[T]) insertInterval(interval *Interval[T]) { | |
| 	prev := list.head | |
| 	next := prev.Next | |
| 
 | |
| 	for interval.StartOffset < interval.StopOffset { | |
| 		if next == nil { | |
| 			// add to the end | |
| 			list.insertBetween(prev, interval, list.tail) | |
| 			break | |
| 		} | |
| 
 | |
| 		// interval is ahead of the next | |
| 		if interval.StopOffset <= next.StartOffset { | |
| 			list.insertBetween(prev, interval, next) | |
| 			break | |
| 		} | |
| 
 | |
| 		// interval is after the next | |
| 		if next.StopOffset <= interval.StartOffset { | |
| 			prev = next | |
| 			next = next.Next | |
| 			continue | |
| 		} | |
| 
 | |
| 		// intersecting next and interval | |
| 		if interval.TsNs >= next.TsNs { | |
| 			// interval is newer | |
| 			if next.StartOffset < interval.StartOffset { | |
| 				// left side of next is ahead of interval | |
| 				t := &Interval[T]{ | |
| 					StartOffset: next.StartOffset, | |
| 					StopOffset:  interval.StartOffset, | |
| 					TsNs:        next.TsNs, | |
| 					Value:       next.Value.Clone().(T), | |
| 				} | |
| 				t.Value.SetStartStop(t.StartOffset, t.StopOffset) | |
| 				list.insertBetween(prev, t, interval) | |
| 				next.StartOffset = interval.StartOffset | |
| 				next.Value.SetStartStop(next.StartOffset, next.StopOffset) | |
| 				prev = t | |
| 			} | |
| 			if interval.StopOffset < next.StopOffset { | |
| 				// right side of next is after interval | |
| 				next.StartOffset = interval.StopOffset | |
| 				next.Value.SetStartStop(next.StartOffset, next.StopOffset) | |
| 				list.insertBetween(prev, interval, next) | |
| 				break | |
| 			} else { | |
| 				// next is covered | |
| 				prev.Next = interval | |
| 				next = next.Next | |
| 			} | |
| 		} else { | |
| 			// next is newer | |
| 			if interval.StartOffset < next.StartOffset { | |
| 				// left side of interval is ahead of next | |
| 				t := &Interval[T]{ | |
| 					StartOffset: interval.StartOffset, | |
| 					StopOffset:  next.StartOffset, | |
| 					TsNs:        interval.TsNs, | |
| 					Value:       interval.Value.Clone().(T), | |
| 				} | |
| 				t.Value.SetStartStop(t.StartOffset, t.StopOffset) | |
| 				list.insertBetween(prev, t, next) | |
| 				interval.StartOffset = next.StartOffset | |
| 				interval.Value.SetStartStop(interval.StartOffset, interval.StopOffset) | |
| 			} | |
| 			if next.StopOffset < interval.StopOffset { | |
| 				// right side of interval is after next | |
| 				interval.StartOffset = next.StopOffset | |
| 				interval.Value.SetStartStop(interval.StartOffset, interval.StopOffset) | |
| 			} else { | |
| 				// interval is covered | |
| 				break | |
| 			} | |
| 		} | |
| 
 | |
| 	} | |
| } | |
| 
 | |
| func (list *IntervalList[T]) insertBetween(a, interval, b *Interval[T]) { | |
| 	a.Next = interval | |
| 	b.Prev = interval | |
| 	if a != list.head { | |
| 		interval.Prev = a | |
| 	} | |
| 	if b != list.tail { | |
| 		interval.Next = b | |
| 	} | |
| } | |
| 
 | |
| func (list *IntervalList[T]) overlayInterval(interval *Interval[T]) { | |
| 
 | |
| 	//t := list.head | |
| 	//for ; t.Next != nil; t = t.Next { | |
| 	//	if t.TsNs > interval.TsNs { | |
| 	//		println("writes is out of order", t.TsNs-interval.TsNs, "ns") | |
| 	//	} | |
| 	//} | |
|  | |
| 	p := list.head | |
| 	for ; p.Next != nil && p.Next.StopOffset <= interval.StartOffset; p = p.Next { | |
| 	} | |
| 	q := list.tail | |
| 	for ; q.Prev != nil && q.Prev.StartOffset >= interval.StopOffset; q = q.Prev { | |
| 	} | |
| 
 | |
| 	// left side | |
| 	// interval after p.Next start | |
| 	if p.Next != nil && p.Next.StartOffset < interval.StartOffset { | |
| 		t := &Interval[T]{ | |
| 			StartOffset: p.Next.StartOffset, | |
| 			StopOffset:  interval.StartOffset, | |
| 			TsNs:        p.Next.TsNs, | |
| 			Value:       p.Next.Value, | |
| 		} | |
| 		p.Next = t | |
| 		if p != list.head { | |
| 			t.Prev = p | |
| 		} | |
| 		t.Next = interval | |
| 		interval.Prev = t | |
| 	} else { | |
| 		p.Next = interval | |
| 		if p != list.head { | |
| 			interval.Prev = p | |
| 		} | |
| 	} | |
| 
 | |
| 	// right side | |
| 	// interval ends before p.Prev | |
| 	if q.Prev != nil && interval.StopOffset < q.Prev.StopOffset { | |
| 		t := &Interval[T]{ | |
| 			StartOffset: interval.StopOffset, | |
| 			StopOffset:  q.Prev.StopOffset, | |
| 			TsNs:        q.Prev.TsNs, | |
| 			Value:       q.Prev.Value, | |
| 		} | |
| 		q.Prev = t | |
| 		if q != list.tail { | |
| 			t.Next = q | |
| 		} | |
| 		interval.Next = t | |
| 		t.Prev = interval | |
| 	} else { | |
| 		q.Prev = interval | |
| 		if q != list.tail { | |
| 			interval.Next = q | |
| 		} | |
| 	} | |
| 
 | |
| } | |
| 
 | |
| func (list *IntervalList[T]) Len() int { | |
| 	list.Lock.RLock() | |
| 	defer list.Lock.RUnlock() | |
| 
 | |
| 	var count int | |
| 	for t := list.head; t != nil; t = t.Next { | |
| 		count++ | |
| 	} | |
| 	return count - 1 | |
| }
 |