fix(selectivity): ensure selectivity dump has no stale data#1214
fix(selectivity): ensure selectivity dump has no stale data#1214KuznetsovRoman merged 2 commits intomasterfrom
Conversation
commit: |
2527862 to
19810a9
Compare
| dependencies.modules.forEach(dependency => this._addModuleDependency(dependency)); | ||
| } | ||
|
|
||
| async commit(): Promise<void> { |
There was a problem hiding this comment.
Removing logic to "not remove anything extra"
It was useful when hash writes were concurrent
| } | ||
|
|
||
| // File was not used in this run | ||
| if (fileStat.atimeMs < performance.timeOrigin && fileStat.isFile()) { |
There was a problem hiding this comment.
"atime" - time file was accessed
"clearUnusedSelectivityDumps" is called after successful run
If file was not accessed in successful run, we can safely delete it
| try { | ||
| const stats = await libUVLimited(() => fs.stat(flagFilePath)); | ||
| return stats.mtimeMs >= processStartTime; | ||
| return stats.mtimeMs >= performance.timeOrigin; |
There was a problem hiding this comment.
Turns out, there is special value for that, so we dont need "new Date()" hacks
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 19810a9bc8
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| await writeTo(this._stagedFileHashes, fileContents.files); | ||
| await writeTo(this._stagedModuleHashes, fileContents.modules); | ||
| await writeTo(this._stagedPatternHashes, fileContents.patterns); | ||
|
|
||
| markAsCommited(updatedModules, this._stagedModuleHashes); | ||
| markAsCommited(updatedFiles, this._stagedFileHashes); | ||
| await writeJsonWithCompression(this._selectivityHashesPath, fileContents, this._compresion); |
There was a problem hiding this comment.
Merge existing hashes before overwriting hashes.json
HashWriter.save now writes a brand-new hash object populated only from currently staged entries, but staging is filled only from executed tests (onTestDependencies) and changed disable patterns (updateSelectivityHashes). This drops hashes for skipped tests and unchanged patterns, so on the next process run HashReader.getTestChangedDeps/patternHasChanged read undefined and treat those dependencies as changed, causing selectivity to rerun tests (or whole browsers) even when source files are unchanged.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
now writes a brand-new hash object populated only from currently staged entries
Yes.
but staging is filled only from executed tests
No. It is also filled in master thread while calculating current file hashes.
and changed disable patterns
Unchanged too. For same reasons.
| } | ||
|
|
||
| // File was not used in this run | ||
| if (fileStat.atimeMs < performance.timeOrigin && fileStat.isFile()) { |
There was a problem hiding this comment.
Stop using atime as a per-run usage marker
The stale-file check deletes dumps based on fileStat.atimeMs < performance.timeOrigin, but on filesystems mounted with relatime/noatime a read during this run may not update atime, so actively used dependency dumps can still look stale and get removed. In those environments, the cleanup step can delete valid selectivity dumps and force unnecessary full reruns on the next execution.
Useful? React with 👍 / 👎.
|
|
||
| if (accessError) { | ||
| if (!("code" in accessError && accessError.code === "ENOENT")) { | ||
| debugSelectivity(`Couldn't access "${testsPath}" to clear stale files: %O`, accessError); |
There was a problem hiding this comment.
Those are debug logs, are they supposed to be actionable to user?
I thought, they need to be clear to us
|
|
||
| for (const browserId of browserIds) { | ||
| const browserConfig = config.forBrowser(browserId); | ||
| const { enabled, testDependenciesPath } = browserConfig.selectivity; |
There was a problem hiding this comment.
but if I use grep option, selectivity will be disabled, right?
There was a problem hiding this comment.
"clearUnusedSelectivityDumps" is called in "testplane.ts" inside:
if (!shouldDisableSelectivity && !this.isFailed())branch, with "updateSelectivityHashes" function call.
Both will not be called because "shouldDisableSelectivity" will be "true" in this case (because of "grep")
| filesDeleted++; | ||
| }) | ||
| .catch(err => { | ||
| debugSelectivity(`Couldn't remove stale file "${filePath}": %O`, err); |
There was a problem hiding this comment.
Since there are plenty of code like this, i will address the issue "actionable fs-errors" in the following pr to avoid code duplication + merge issues
| assert.calledOnce(getSelectivityTestsPathStub); | ||
| assert.calledWith(getSelectivityTestsPathStub, "/test/deps"); | ||
| assert.calledOnce(fsStub.access); | ||
| assert.calledWith(fsStub.access, "/test/deps/tests", 6); // R_OK | W_OK = 4 | 2 = 6 |
There was a problem hiding this comment.
Not quite.
0b00000100
0b00000010
0b00000110
Its bitwise "or", not "sum"
19810a9 to
93c7d77
Compare
93c7d77 to
af5b616
Compare
No description provided.