Closed AskAlexSharov closed 1 day ago
Read aggregator related files and find (maybe) a potential issue.
Here between if refCnt == 0 && src.canDelete.Load()
and src.closeFilesAndRemove()
can happen BeginFilesRo
, which may cause nil-ptr.
refCnt := src.refcount.Add(-1)
//GC: last reader responsible to remove useles files: close it and delete
if refCnt == 0 && src.canDelete.Load() {
if traceFileLife != "" && tx.ap.filenameBase == traceFileLife {
tx.ap.logger.Warn("[agg.dbg] real remove at AppendableRoTx.Close", "file", src.decompressor.FileName())
}
src.closeFilesAndRemove()
}
I haven't read every detail so just suspect. Maybe it never happens.
Continue working on #11417...
Maybe you right: assumption is - files with canDelete.True() will not be visible for new readers (see recalcVisibleFiles).
Anyway we need use atomic.Int and maybe runtime-check negative refcnt
@stevemilk FYI: i have perf requirements for agg.BeginRo - it must be lock-free zero-allocation - because it’s what will be called in each RPC request. And we have tons of parallel RPS (throughput) - because “node providers” using us.
So, i believe in far future RoSnapshots (introduced in E2) also will have zero-alloc lock-free View method. (“lock-free” - atomics are fine, RwMutex - nope). It’s for future - not for now.
This is reason why I want separation of visible/dirty files - then write to visibleFiles will happen only in 1 atomic place: recalcVisibleFiles()
assumption is - files with canDelete.True() will not be visible for new readers (see recalcVisibleFiles).
mark canDelete as true
and recalcVisibleFiles
is not atomic, so the assumption could be broken in a small probability - corner case.
This is reason why I want separation of visible/dirty files - then write to visibleFiles will happen only in 1 atomic place: recalcVisibleFiles()
I totally agree with the design. For segments race issue, separation plus #11430 can make indexed segments append-only and avoid race. And for the above corner case, the complexity comes from showing small files that are going to be merged. Will you consider setting files to visible after files are merged/ no need to be merged ? If so, visible files become append-only.
Files are visible after merged and indexed, and after _visible.Store(_dirty.calcVisibleFiles())
updates:
Example from state files in E3:
Means all Open/Reopen/Build/Merge operations - are working with
_dirtyFiles
as much as they want, thenrecalcVisibleFiles()
called once - which creating NEW list of visible files and saves in_visibleFiles
, then all RPC requests just uselist := _visibleFiles.Load()
(mutex-free) andlist
guarantee to be always immutable.func (a *Aggregator) Close
can just wait until all existingroTx
are finishFrom E3 docs:
I think this task will solve next issue: