| 
									
										
										
										
											2020-02-13 03:22:27 +08:00
										 |  |  | // Copyright 2020 The Prometheus Authors
 | 
					
						
							|  |  |  | // Licensed under the Apache License, Version 2.0 (the "License");
 | 
					
						
							|  |  |  | // you may not use this file except in compliance with the License.
 | 
					
						
							|  |  |  | // You may obtain a copy of the License at
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // http://www.apache.org/licenses/LICENSE-2.0
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Unless required by applicable law or agreed to in writing, software
 | 
					
						
							|  |  |  | // distributed under the License is distributed on an "AS IS" BASIS,
 | 
					
						
							|  |  |  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
					
						
							|  |  |  | // See the License for the specific language governing permissions and
 | 
					
						
							|  |  |  | // limitations under the License.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package tsdb | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2022-09-27 22:01:23 +08:00
										 |  |  | 	"math" | 
					
						
							| 
									
										
										
										
											2020-02-13 03:22:27 +08:00
										 |  |  | 	"sync" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // isolationState holds the isolation information.
 | 
					
						
							|  |  |  | type isolationState struct { | 
					
						
							|  |  |  | 	// We will ignore all appends above the max, or that are incomplete.
 | 
					
						
							|  |  |  | 	maxAppendID       uint64 | 
					
						
							|  |  |  | 	incompleteAppends map[uint64]struct{} | 
					
						
							|  |  |  | 	lowWatermark      uint64 // Lowest of incompleteAppends/maxAppendID.
 | 
					
						
							|  |  |  | 	isolation         *isolation | 
					
						
							| 
									
										
										
										
											2021-07-20 16:47:20 +08:00
										 |  |  | 	mint, maxt        int64 // Time ranges of the read.
 | 
					
						
							| 
									
										
										
										
											2020-02-13 03:22:27 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Doubly linked list of active reads.
 | 
					
						
							|  |  |  | 	next *isolationState | 
					
						
							|  |  |  | 	prev *isolationState | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Close closes the state.
 | 
					
						
							|  |  |  | func (i *isolationState) Close() { | 
					
						
							|  |  |  | 	i.isolation.readMtx.Lock() | 
					
						
							|  |  |  | 	defer i.isolation.readMtx.Unlock() | 
					
						
							|  |  |  | 	i.next.prev = i.prev | 
					
						
							|  |  |  | 	i.prev.next = i.next | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-19 18:11:32 +08:00
										 |  |  | func (i *isolationState) IsolationDisabled() bool { | 
					
						
							|  |  |  | 	return i.isolation.disabled | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-04 02:09:05 +08:00
										 |  |  | type isolationAppender struct { | 
					
						
							|  |  |  | 	appendID uint64 | 
					
						
							| 
									
										
										
										
											2022-09-27 22:01:23 +08:00
										 |  |  | 	minTime  int64 | 
					
						
							| 
									
										
										
										
											2020-06-04 02:09:05 +08:00
										 |  |  | 	prev     *isolationAppender | 
					
						
							|  |  |  | 	next     *isolationAppender | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-13 03:22:27 +08:00
										 |  |  | // isolation is the global isolation state.
 | 
					
						
							|  |  |  | type isolation struct { | 
					
						
							|  |  |  | 	// Mutex for accessing lastAppendID and appendsOpen.
 | 
					
						
							| 
									
										
										
										
											2020-06-04 02:09:05 +08:00
										 |  |  | 	appendMtx sync.RWMutex | 
					
						
							| 
									
										
										
										
											2020-02-13 03:22:27 +08:00
										 |  |  | 	// Which appends are currently in progress.
 | 
					
						
							| 
									
										
										
										
											2020-06-04 02:09:05 +08:00
										 |  |  | 	appendsOpen map[uint64]*isolationAppender | 
					
						
							|  |  |  | 	// New appenders with higher appendID are added to the end. First element keeps lastAppendId.
 | 
					
						
							|  |  |  | 	// appendsOpenList.next points to the first element and appendsOpenList.prev points to the last element.
 | 
					
						
							|  |  |  | 	// If there are no appenders, both point back to appendsOpenList.
 | 
					
						
							|  |  |  | 	appendsOpenList *isolationAppender | 
					
						
							|  |  |  | 	// Pool of reusable *isolationAppender to save on allocations.
 | 
					
						
							|  |  |  | 	appendersPool sync.Pool | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-13 03:22:27 +08:00
										 |  |  | 	// Mutex for accessing readsOpen.
 | 
					
						
							|  |  |  | 	// If taking both appendMtx and readMtx, take appendMtx first.
 | 
					
						
							| 
									
										
										
										
											2020-06-04 02:09:05 +08:00
										 |  |  | 	readMtx sync.RWMutex | 
					
						
							| 
									
										
										
										
											2020-02-13 03:22:27 +08:00
										 |  |  | 	// All current in use isolationStates. This is a doubly-linked list.
 | 
					
						
							|  |  |  | 	readsOpen *isolationState | 
					
						
							| 
									
										
										
										
											2021-11-19 18:11:32 +08:00
										 |  |  | 	// If true, writes are not tracked while reads are still tracked.
 | 
					
						
							|  |  |  | 	disabled bool | 
					
						
							| 
									
										
										
										
											2020-02-13 03:22:27 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-19 18:11:32 +08:00
										 |  |  | func newIsolation(disabled bool) *isolation { | 
					
						
							| 
									
										
										
										
											2020-02-13 03:22:27 +08:00
										 |  |  | 	isoState := &isolationState{} | 
					
						
							|  |  |  | 	isoState.next = isoState | 
					
						
							|  |  |  | 	isoState.prev = isoState | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-04 02:09:05 +08:00
										 |  |  | 	appender := &isolationAppender{} | 
					
						
							|  |  |  | 	appender.next = appender | 
					
						
							|  |  |  | 	appender.prev = appender | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-13 03:22:27 +08:00
										 |  |  | 	return &isolation{ | 
					
						
							| 
									
										
										
										
											2020-06-04 02:09:05 +08:00
										 |  |  | 		appendsOpen:     map[uint64]*isolationAppender{}, | 
					
						
							|  |  |  | 		appendsOpenList: appender, | 
					
						
							|  |  |  | 		readsOpen:       isoState, | 
					
						
							| 
									
										
										
										
											2021-11-19 18:11:32 +08:00
										 |  |  | 		disabled:        disabled, | 
					
						
							| 
									
										
										
										
											2020-06-04 02:09:05 +08:00
										 |  |  | 		appendersPool:   sync.Pool{New: func() interface{} { return &isolationAppender{} }}, | 
					
						
							| 
									
										
										
										
											2020-02-13 03:22:27 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // lowWatermark returns the appendID below which we no longer need to track
 | 
					
						
							|  |  |  | // which appends were from which appendID.
 | 
					
						
							|  |  |  | func (i *isolation) lowWatermark() uint64 { | 
					
						
							| 
									
										
										
										
											2021-11-19 18:11:32 +08:00
										 |  |  | 	if i.disabled { | 
					
						
							|  |  |  | 		return 0 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-04 02:09:05 +08:00
										 |  |  | 	i.appendMtx.RLock() // Take appendMtx first.
 | 
					
						
							|  |  |  | 	defer i.appendMtx.RUnlock() | 
					
						
							| 
									
										
										
										
											2021-07-07 21:28:20 +08:00
										 |  |  | 	return i.lowWatermarkLocked() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (i *isolation) lowWatermarkLocked() uint64 { | 
					
						
							| 
									
										
										
										
											2021-11-19 18:11:32 +08:00
										 |  |  | 	if i.disabled { | 
					
						
							|  |  |  | 		return 0 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-04 02:09:05 +08:00
										 |  |  | 	i.readMtx.RLock() | 
					
						
							|  |  |  | 	defer i.readMtx.RUnlock() | 
					
						
							| 
									
										
										
										
											2020-02-13 03:22:27 +08:00
										 |  |  | 	if i.readsOpen.prev != i.readsOpen { | 
					
						
							|  |  |  | 		return i.readsOpen.prev.lowWatermark | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-06-04 02:09:05 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Lowest appendID from appenders, or lastAppendId.
 | 
					
						
							|  |  |  | 	return i.appendsOpenList.next.appendID | 
					
						
							| 
									
										
										
										
											2020-02-13 03:22:27 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-27 22:01:23 +08:00
										 |  |  | // lowestAppendTime returns the lowest minTime for any open appender,
 | 
					
						
							|  |  |  | // or math.MaxInt64 if no open appenders.
 | 
					
						
							|  |  |  | func (i *isolation) lowestAppendTime() int64 { | 
					
						
							|  |  |  | 	var lowest int64 = math.MaxInt64 | 
					
						
							|  |  |  | 	i.appendMtx.RLock() | 
					
						
							|  |  |  | 	defer i.appendMtx.RUnlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for a := i.appendsOpenList.next; a != i.appendsOpenList; a = a.next { | 
					
						
							|  |  |  | 		if lowest > a.minTime { | 
					
						
							|  |  |  | 			lowest = a.minTime | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return lowest | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-13 03:22:27 +08:00
										 |  |  | // State returns an object used to control isolation
 | 
					
						
							|  |  |  | // between a query and appends. Must be closed when complete.
 | 
					
						
							| 
									
										
										
										
											2021-07-20 16:47:20 +08:00
										 |  |  | func (i *isolation) State(mint, maxt int64) *isolationState { | 
					
						
							| 
									
										
										
										
											2020-06-04 02:09:05 +08:00
										 |  |  | 	i.appendMtx.RLock() // Take append mutex before read mutex.
 | 
					
						
							|  |  |  | 	defer i.appendMtx.RUnlock() | 
					
						
							| 
									
										
										
										
											2021-11-19 18:11:32 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-13 17:11:03 +08:00
										 |  |  | 	// We need to track reads even when isolation is disabled, so that head
 | 
					
						
							|  |  |  | 	// truncation can wait till reads overlapping that range have finished.
 | 
					
						
							| 
									
										
										
										
											2020-02-13 03:22:27 +08:00
										 |  |  | 	isoState := &isolationState{ | 
					
						
							| 
									
										
										
										
											2020-06-04 02:09:05 +08:00
										 |  |  | 		maxAppendID:       i.appendsOpenList.appendID, | 
					
						
							|  |  |  | 		lowWatermark:      i.appendsOpenList.next.appendID, // Lowest appendID from appenders, or lastAppendId.
 | 
					
						
							| 
									
										
										
										
											2020-02-13 03:22:27 +08:00
										 |  |  | 		incompleteAppends: make(map[uint64]struct{}, len(i.appendsOpen)), | 
					
						
							|  |  |  | 		isolation:         i, | 
					
						
							| 
									
										
										
										
											2021-07-20 16:47:20 +08:00
										 |  |  | 		mint:              mint, | 
					
						
							|  |  |  | 		maxt:              maxt, | 
					
						
							| 
									
										
										
										
											2020-02-13 03:22:27 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	for k := range i.appendsOpen { | 
					
						
							|  |  |  | 		isoState.incompleteAppends[k] = struct{}{} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	i.readMtx.Lock() | 
					
						
							|  |  |  | 	defer i.readMtx.Unlock() | 
					
						
							|  |  |  | 	isoState.prev = i.readsOpen | 
					
						
							|  |  |  | 	isoState.next = i.readsOpen.next | 
					
						
							|  |  |  | 	i.readsOpen.next.prev = isoState | 
					
						
							|  |  |  | 	i.readsOpen.next = isoState | 
					
						
							| 
									
										
										
										
											2021-11-19 18:11:32 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-13 03:22:27 +08:00
										 |  |  | 	return isoState | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-20 16:47:20 +08:00
										 |  |  | // TraverseOpenReads iterates through the open reads and runs the given
 | 
					
						
							|  |  |  | // function on those states. The given function MUST NOT mutate the isolationState.
 | 
					
						
							|  |  |  | // The iteration is stopped when the function returns false or once all reads have been iterated.
 | 
					
						
							|  |  |  | func (i *isolation) TraverseOpenReads(f func(s *isolationState) bool) { | 
					
						
							|  |  |  | 	i.readMtx.RLock() | 
					
						
							|  |  |  | 	defer i.readMtx.RUnlock() | 
					
						
							|  |  |  | 	s := i.readsOpen.next | 
					
						
							|  |  |  | 	for s != i.readsOpen { | 
					
						
							|  |  |  | 		if !f(s) { | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		s = s.next | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-29 09:39:26 +08:00
										 |  |  | // newAppendID increments the transaction counter and returns a new transaction
 | 
					
						
							|  |  |  | // ID. The first ID returned is 1.
 | 
					
						
							| 
									
										
										
										
											2021-07-29 18:38:11 +08:00
										 |  |  | // Also returns the low watermark, to keep lock/unlock operations down.
 | 
					
						
							| 
									
										
										
										
											2022-09-27 22:01:23 +08:00
										 |  |  | func (i *isolation) newAppendID(minTime int64) (uint64, uint64) { | 
					
						
							| 
									
										
										
										
											2021-11-19 18:11:32 +08:00
										 |  |  | 	if i.disabled { | 
					
						
							|  |  |  | 		return 0, 0 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-13 03:22:27 +08:00
										 |  |  | 	i.appendMtx.Lock() | 
					
						
							|  |  |  | 	defer i.appendMtx.Unlock() | 
					
						
							| 
									
										
										
										
											2020-06-04 02:09:05 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Last used appendID is stored in head element.
 | 
					
						
							|  |  |  | 	i.appendsOpenList.appendID++ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	app := i.appendersPool.Get().(*isolationAppender) | 
					
						
							|  |  |  | 	app.appendID = i.appendsOpenList.appendID | 
					
						
							| 
									
										
										
										
											2022-09-27 22:01:23 +08:00
										 |  |  | 	app.minTime = minTime | 
					
						
							| 
									
										
										
										
											2020-06-04 02:09:05 +08:00
										 |  |  | 	app.prev = i.appendsOpenList.prev | 
					
						
							|  |  |  | 	app.next = i.appendsOpenList | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	i.appendsOpenList.prev.next = app | 
					
						
							|  |  |  | 	i.appendsOpenList.prev = app | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	i.appendsOpen[app.appendID] = app | 
					
						
							| 
									
										
										
										
											2021-07-07 21:28:20 +08:00
										 |  |  | 	return app.appendID, i.lowWatermarkLocked() | 
					
						
							| 
									
										
										
										
											2020-06-04 02:09:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (i *isolation) lastAppendID() uint64 { | 
					
						
							| 
									
										
										
										
											2021-11-19 18:11:32 +08:00
										 |  |  | 	if i.disabled { | 
					
						
							|  |  |  | 		return 0 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-04 02:09:05 +08:00
										 |  |  | 	i.appendMtx.RLock() | 
					
						
							|  |  |  | 	defer i.appendMtx.RUnlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return i.appendsOpenList.appendID | 
					
						
							| 
									
										
										
										
											2020-02-13 03:22:27 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (i *isolation) closeAppend(appendID uint64) { | 
					
						
							| 
									
										
										
										
											2021-11-19 18:11:32 +08:00
										 |  |  | 	if i.disabled { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-13 03:22:27 +08:00
										 |  |  | 	i.appendMtx.Lock() | 
					
						
							|  |  |  | 	defer i.appendMtx.Unlock() | 
					
						
							| 
									
										
										
										
											2020-06-04 02:09:05 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	app := i.appendsOpen[appendID] | 
					
						
							|  |  |  | 	if app != nil { | 
					
						
							|  |  |  | 		app.prev.next = app.next | 
					
						
							|  |  |  | 		app.next.prev = app.prev | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		delete(i.appendsOpen, appendID) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Clear all fields, and return to the pool.
 | 
					
						
							|  |  |  | 		*app = isolationAppender{} | 
					
						
							|  |  |  | 		i.appendersPool.Put(app) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-02-13 03:22:27 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // The transactionID ring buffer.
 | 
					
						
							|  |  |  | type txRing struct { | 
					
						
							|  |  |  | 	txIDs     []uint64 | 
					
						
							| 
									
										
										
										
											2023-10-21 20:38:01 +08:00
										 |  |  | 	txIDFirst uint32 // Position of the first id in the ring.
 | 
					
						
							|  |  |  | 	txIDCount uint32 // How many ids in the ring.
 | 
					
						
							| 
									
										
										
										
											2020-02-13 03:22:27 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-21 15:20:07 +08:00
										 |  |  | func newTxRing(capacity int) *txRing { | 
					
						
							| 
									
										
										
										
											2020-02-13 03:22:27 +08:00
										 |  |  | 	return &txRing{ | 
					
						
							| 
									
										
										
										
											2023-05-21 15:20:07 +08:00
										 |  |  | 		txIDs: make([]uint64, capacity), | 
					
						
							| 
									
										
										
										
											2020-02-13 03:22:27 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (txr *txRing) add(appendID uint64) { | 
					
						
							| 
									
										
										
										
											2023-10-21 20:38:01 +08:00
										 |  |  | 	if int(txr.txIDCount) == len(txr.txIDs) { | 
					
						
							| 
									
										
										
										
											2020-02-13 03:22:27 +08:00
										 |  |  | 		// Ring buffer is full, expand by doubling.
 | 
					
						
							| 
									
										
										
										
											2023-10-21 21:45:47 +08:00
										 |  |  | 		newLen := txr.txIDCount * 2 | 
					
						
							|  |  |  | 		if newLen == 0 { | 
					
						
							|  |  |  | 			newLen = 4 | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		newRing := make([]uint64, newLen) | 
					
						
							| 
									
										
										
										
											2023-04-09 15:08:40 +08:00
										 |  |  | 		idx := copy(newRing, txr.txIDs[txr.txIDFirst:]) | 
					
						
							| 
									
										
										
										
											2020-02-13 03:22:27 +08:00
										 |  |  | 		copy(newRing[idx:], txr.txIDs[:txr.txIDFirst]) | 
					
						
							|  |  |  | 		txr.txIDs = newRing | 
					
						
							|  |  |  | 		txr.txIDFirst = 0 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-21 20:38:01 +08:00
										 |  |  | 	txr.txIDs[int(txr.txIDFirst+txr.txIDCount)%len(txr.txIDs)] = appendID | 
					
						
							| 
									
										
										
										
											2020-02-13 03:22:27 +08:00
										 |  |  | 	txr.txIDCount++ | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (txr *txRing) cleanupAppendIDsBelow(bound uint64) { | 
					
						
							| 
									
										
										
										
											2023-10-21 21:45:47 +08:00
										 |  |  | 	if len(txr.txIDs) == 0 { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-10-21 20:38:01 +08:00
										 |  |  | 	pos := int(txr.txIDFirst) | 
					
						
							| 
									
										
										
										
											2020-02-13 03:22:27 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	for txr.txIDCount > 0 { | 
					
						
							| 
									
										
										
										
											2025-02-11 04:20:48 +08:00
										 |  |  | 		if txr.txIDs[pos] >= bound { | 
					
						
							| 
									
										
										
										
											2020-02-13 03:22:27 +08:00
										 |  |  | 			break | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2025-02-11 04:20:48 +08:00
										 |  |  | 		txr.txIDFirst++ | 
					
						
							|  |  |  | 		txr.txIDCount-- | 
					
						
							| 
									
										
										
										
											2020-02-13 03:22:27 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		pos++ | 
					
						
							|  |  |  | 		if pos == len(txr.txIDs) { | 
					
						
							|  |  |  | 			pos = 0 | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-21 20:38:01 +08:00
										 |  |  | 	txr.txIDFirst %= uint32(len(txr.txIDs)) | 
					
						
							| 
									
										
										
										
											2020-02-13 03:22:27 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (txr *txRing) iterator() *txRingIterator { | 
					
						
							|  |  |  | 	return &txRingIterator{ | 
					
						
							|  |  |  | 		pos: txr.txIDFirst, | 
					
						
							|  |  |  | 		ids: txr.txIDs, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // txRingIterator lets you iterate over the ring. It doesn't terminate,
 | 
					
						
							|  |  |  | // it DOESN'T terminate.
 | 
					
						
							|  |  |  | type txRingIterator struct { | 
					
						
							|  |  |  | 	ids []uint64 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-21 20:38:01 +08:00
										 |  |  | 	pos uint32 | 
					
						
							| 
									
										
										
										
											2020-02-13 03:22:27 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (it *txRingIterator) At() uint64 { | 
					
						
							|  |  |  | 	return it.ids[it.pos] | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (it *txRingIterator) Next() { | 
					
						
							|  |  |  | 	it.pos++ | 
					
						
							| 
									
										
										
										
											2023-10-21 20:38:01 +08:00
										 |  |  | 	if int(it.pos) == len(it.ids) { | 
					
						
							| 
									
										
										
										
											2020-02-13 03:22:27 +08:00
										 |  |  | 		it.pos = 0 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |