| 1 | package sessioncatalog |
| 2 | |
| 3 | // pathMutationAllowed applies the remove-versus-recreate generation rule at |
| 4 | // every writer boundary. A candidate newer than the observed removal may clear |
| 5 | // exactly that tombstone; if another removal replaces it concurrently, the |
| 6 | // compare fails and the candidate is re-evaluated against the newer generation. |
| 7 | func (c *Catalog) pathMutationAllowed(pathKey string, sequence uint64) bool { |
| 8 | for { |
| 9 | removedAt, removed := c.removedPaths.Load(pathKey) |
| 10 | if !removed { |
| 11 | return true |
| 12 | } |
| 13 | if c.testPathMutationLoadedHook != nil { |
| 14 | c.testPathMutationLoadedHook(pathKey) |
| 15 | } |
| 16 | removedSequence, ok := removedAt.(uint64) |
| 17 | if !ok || sequence <= removedSequence { |
| 18 | return false |
| 19 | } |
| 20 | if c.removedPaths.CompareAndDelete(pathKey, removedAt) { |
| 21 | return true |
| 22 | } |
| 23 | } |
| 24 | } |
| 25 | |
| 26 | func (c *Catalog) filterPathMutations(records []SessionRecord, sequence uint64) []SessionRecord { |
| 27 | filtered := records[:0] |
| 28 | for _, record := range records { |
| 29 | if c.pathMutationAllowed(c.pathKey(record.Path), sequence) { |
| 30 | record.enqueueSequence = sequence |
| 31 | filtered = append(filtered, record) |
| 32 | } |
| 33 | } |
| 34 | return filtered |
| 35 | } |
| 36 |