Unified · Split
| @@ -97,6 +97,72 @@ type childBucket struct { · 96 unmodified lines | |||
| 97 | // cooldownQueue is the blocked auth collection ordered by next retry time during rebuilds. | 97 | // cooldownQueue is the blocked auth collection ordered by next retry time during rebuilds. |
| 98 | type cooldownQueue []*scheduledAuth | 98 | type cooldownQueue []*scheduledAuth |
| 99 | 99 | ||
| 100 | type readyViewCursorState struct { | ||
| 101 | cursor int | ||
| 102 | parentCursor int | ||
| 103 | childCursors map[string]int | ||
| 104 | } | ||
| 105 | |||
| 106 | type readyBucketCursorState struct { | ||
| 107 | all readyViewCursorState | ||
| 108 | ws readyViewCursorState | ||
| 109 | } | ||
| 110 | |||
| 111 | func snapshotReadyViewCursors(view readyView) readyViewCursorState { | ||
| 112 | state := readyViewCursorState{ | ||
| 113 | cursor: view.cursor, | ||
| 114 | parentCursor: view.parentCursor, | ||
| 115 | } | ||
| 116 | if len(view.children) == 0 { | ||
| 117 | return state | ||
| 118 | } | ||
| 119 | state.childCursors = make(map[string]int, len(view.children)) | ||
| 120 | for parent, child := range view.children { | ||
| 121 | if child == nil { | ||
| 122 | continue | ||
| 123 | } | ||
| 124 | state.childCursors[parent] = child.cursor | ||
| 125 | } | ||
| 126 | return state | ||
| 127 | } | ||
| 128 | |||
| 129 | func restoreReadyViewCursors(view *readyView, state readyViewCursorState) { | ||
| 130 | if view == nil { | ||
| 131 | return | ||
| 132 | } | ||
| 133 | if len(view.flat) > 0 { | ||
| 134 | view.cursor = normalizeCursor(state.cursor, len(view.flat)) | ||
| 135 | } | ||
| 136 | if len(view.parentOrder) == 0 || len(view.children) == 0 { | ||
| 137 | return | ||
| 138 | } | ||
| 139 | view.parentCursor = normalizeCursor(state.parentCursor, len(view.parentOrder)) | ||
| 140 | if len(state.childCursors) == 0 { | ||
| 141 | return | ||
| 142 | } | ||
| 143 | for parent, child := range view.children { | ||
| 144 | if child == nil || len(child.items) == 0 { | ||
| 145 | continue | ||
| 146 | } | ||
| 147 | cursor, ok := state.childCursors[parent] | ||
| 148 | if !ok { | ||
| 149 | continue | ||
| 150 | } | ||
| 151 | child.cursor = normalizeCursor(cursor, len(child.items)) | ||
| 152 | } | ||
| 153 | } | ||
| 154 | |||
| 155 | func normalizeCursor(cursor, size int) int { | ||
| 156 | if size <= 0 || cursor <= 0 { | ||
| 157 | return 0 | ||
| 158 | } | ||
| 159 | cursor = cursor % size | ||
| 160 | if cursor < 0 { | ||
| 161 | cursor += size | ||
| 162 | } | ||
| 163 | return cursor | ||
| 164 | } | ||
| 165 | |||
| 100 | // newAuthScheduler constructs an empty scheduler configured for the supplied selector strategy. | 166 | // newAuthScheduler constructs an empty scheduler configured for the supplied selector strategy. |
| 101 | func newAuthScheduler(selector Selector) *authScheduler { | 167 | func newAuthScheduler(selector Selector) *authScheduler { |
| 102 | return &authScheduler{ | 168 | return &authScheduler{ |
| @@ -824,6 +890,17 @@ func (m *modelScheduler) availabilitySummaryLocked(predicate func(*scheduledAuth · 721 unmodified lines | |||
| 824 | 890 | ||
| 825 | // rebuildIndexesLocked reconstructs ready and blocked views from the current entry map. | 891 | // rebuildIndexesLocked reconstructs ready and blocked views from the current entry map. |
| 826 | func (m *modelScheduler) rebuildIndexesLocked() { | 892 | func (m *modelScheduler) rebuildIndexesLocked() { |
| 893 | cursorStates := make(map[int]readyBucketCursorState, len(m.readyByPriority)) | ||
| 894 | for priority, bucket := range m.readyByPriority { | ||
| 895 | if bucket == nil { | ||
| 896 | continue | ||
| 897 | } | ||
| 898 | cursorStates[priority] = readyBucketCursorState{ | ||
| 899 | all: snapshotReadyViewCursors(bucket.all), | ||
| 900 | ws: snapshotReadyViewCursors(bucket.ws), | ||
| 901 | } | ||
| 902 | } | ||
| 903 | |||
| 827 | m.readyByPriority = make(map[int]*readyBucket) | 904 | m.readyByPriority = make(map[int]*readyBucket) |
| 828 | m.priorityOrder = m.priorityOrder[:0] | 905 | m.priorityOrder = m.priorityOrder[:0] |
| 829 | m.blocked = m.blocked[:0] | 906 | m.blocked = m.blocked[:0] |
| @@ -844,7 +921,12 @@ func (m *modelScheduler) rebuildIndexesLocked() { · 14 unmodified lines | |||
| 844 | sort.Slice(entries, func(i, j int) bool { | 921 | sort.Slice(entries, func(i, j int) bool { |
| 845 | return entries[i].auth.ID < entries[j].auth.ID | 922 | return entries[i].auth.ID < entries[j].auth.ID |
| 846 | }) | 923 | }) |
| 847 | m.readyByPriority[priority] = buildReadyBucket(entries) | 924 | bucket := buildReadyBucket(entries) |
| 925 | if cursorState, ok := cursorStates[priority]; ok && bucket != nil { | ||
| 926 | restoreReadyViewCursors(&bucket.all, cursorState.all) | ||
| 927 | restoreReadyViewCursors(&bucket.ws, cursorState.ws) | ||
| 928 | } | ||
| 929 | m.readyByPriority[priority] = bucket | ||
| 848 | m.priorityOrder = append(m.priorityOrder, priority) | 930 | m.priorityOrder = append(m.priorityOrder, priority) |
| 849 | } | 931 | } |
| 850 | sort.Slice(m.priorityOrder, func(i, j int) bool { | 932 | sort.Slice(m.priorityOrder, func(i, j int) bool { |