|
25 | 25 | import com.google.devtools.build.lib.exec.ExecutionOptions;
|
26 | 26 | import com.google.devtools.build.lib.exec.RunfilesTreeUpdater;
|
27 | 27 | import com.google.devtools.build.lib.exec.SpawnStrategyRegistry;
|
28 |
| -import com.google.devtools.build.lib.exec.TreeDeleter; |
29 | 28 | import com.google.devtools.build.lib.exec.local.LocalEnvProvider;
|
30 | 29 | import com.google.devtools.build.lib.runtime.BlazeModule;
|
31 | 30 | import com.google.devtools.build.lib.runtime.BlazeWorkspace;
|
|
46 | 45 |
|
47 | 46 | /** A module that adds the WorkerActionContextProvider to the available action context providers. */
|
48 | 47 | public class WorkerModule extends BlazeModule {
|
| 48 | + |
| 49 | + private static final String STALE_TRASH = "_stale_trash"; |
49 | 50 | private CommandEnvironment env;
|
50 | 51 |
|
51 | 52 | private WorkerFactory workerFactory;
|
52 |
| - private TreeDeleter treeDeleter; |
| 53 | + private AsynchronousTreeDeleter treeDeleter; |
53 | 54 | @VisibleForTesting WorkerPoolImpl workerPool;
|
54 | 55 | @Nullable private WorkerLifecycleManager workerLifecycleManager;
|
55 | 56 |
|
@@ -114,6 +115,9 @@ public void buildStarting(BuildStartingEvent event) {
|
114 | 115 | Path trashBase = workerDir.getRelative(AsynchronousTreeDeleter.MOVED_TRASH_DIR);
|
115 | 116 | if (treeDeleter == null) {
|
116 | 117 | treeDeleter = new AsynchronousTreeDeleter(trashBase);
|
| 118 | + if (trashBase.exists()) { |
| 119 | + removeStaleTrash(workerDir, trashBase); |
| 120 | + } |
117 | 121 | }
|
118 | 122 | WorkerFactory newWorkerFactory =
|
119 | 123 | new WorkerFactory(workerDir, options, workerSandboxOptions, treeDeleter);
|
@@ -185,6 +189,28 @@ public void buildStarting(BuildStartingEvent event) {
|
185 | 189 | workerPool.reset();
|
186 | 190 | }
|
187 | 191 |
|
| 192 | + private void removeStaleTrash(Path workerDir, Path trashBase) { |
| 193 | + try { |
| 194 | + // The AsynchronousTreeDeleter relies on a counter for naming directories that will be |
| 195 | + // moved out of the way before being deleted asynchronously. |
| 196 | + // If there is trash on disk from a previous bazel server instance, the dirs will have |
| 197 | + // names not synced with the counter, therefore we may run the risk of moving a directory |
| 198 | + // in this server instance to a path of an existing directory. To solve this we rename |
| 199 | + // the trash directory that was on disk, create a new empty trash directory and delete |
| 200 | + // the old trash via the AsynchronousTreeDeleter. Before deletion the stale trash will be |
| 201 | + // moved to a directory named `0` under MOVED_TRASH_DIR. |
| 202 | + Path staleTrash = trashBase.getParentDirectory().getChild(STALE_TRASH); |
| 203 | + trashBase.renameTo(staleTrash); |
| 204 | + trashBase.createDirectory(); |
| 205 | + treeDeleter.deleteTree(staleTrash); |
| 206 | + } catch (IOException e) { |
| 207 | + env.getReporter() |
| 208 | + .handle( |
| 209 | + Event.error( |
| 210 | + String.format("Could not trash dir in '%s': %s", workerDir, e.getMessage()))); |
| 211 | + } |
| 212 | + } |
| 213 | + |
188 | 214 | @Override
|
189 | 215 | public void registerSpawnStrategies(
|
190 | 216 | SpawnStrategyRegistry.Builder registryBuilder, CommandEnvironment env) {
|
|
0 commit comments