Bugfix: fix race conditions

This commit is contained in:
2026-08-10 11:07:39 +01:00
parent 44c5c19050
commit 9eae95e391
14 changed files with 326 additions and 175 deletions
+69 -3
View File
@@ -15,10 +15,66 @@ Object.defineProperty(exports, "__esModule", { value: true });
exports.default = sync;
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const os_1 = __importDefault(require("os"));
const util_1 = __importDefault(require("util"));
const crypto_1 = __importDefault(require("crypto"));
const child_process_1 = require("child_process");
const grab_dir_names_1 = __importDefault(require("./grab-dir-names"));
const grab_folders_files_string_paths_1 = require("./grab-folders-files-string-paths");
const delay_1 = __importDefault(require("./delay"));
const execPromise = util_1.default.promisify(child_process_1.exec);
const LOCK_STALE_MS = 5 * 60 * 1000;
const LOCK_RETRY_MS = 100;
function lockPathFor(dirPath) {
const hash = crypto_1.default
.createHash("sha1")
.update(path_1.default.resolve(dirPath))
.digest("hex")
.slice(0, 16);
return path_1.default.join(os_1.default.tmpdir(), `turbosync-${hash}.lock`);
}
function acquireLock(lockPath) {
return __awaiter(this, void 0, void 0, function* () {
while (true) {
try {
const fd = fs_1.default.openSync(lockPath, "wx");
fs_1.default.writeFileSync(fd, String(process.pid));
fs_1.default.closeSync(fd);
return;
}
catch (error) {
if (error.code !== "EEXIST")
throw error;
try {
const { mtimeMs } = fs_1.default.statSync(lockPath);
if (Date.now() - mtimeMs > LOCK_STALE_MS) {
fs_1.default.unlinkSync(lockPath);
continue;
}
}
catch (_a) {
continue;
}
yield (0, delay_1.default)(LOCK_RETRY_MS);
}
}
});
}
function acquireLocks(lockPaths) {
return __awaiter(this, void 0, void 0, function* () {
for (const lockPath of lockPaths) {
yield acquireLock(lockPath);
}
});
}
function releaseLocks(lockPaths) {
for (const lockPath of lockPaths) {
try {
fs_1.default.unlinkSync(lockPath);
}
catch (_a) { }
}
}
function sync(_a) {
return __awaiter(this, arguments, void 0, function* ({ options, dirs, dirPath, isFiles, firstRun, }) {
var _b, _c;
@@ -78,9 +134,19 @@ function sync(_a) {
}
allCommandsArr.push(cmdArray);
}
yield Promise.all(allCommandsArr.map((cmdArr) => {
return execPromise(cmdArr.join(" "));
}));
const lockPaths = [dirPath, ...dstDirs.map((dr) => (0, grab_folders_files_string_paths_1.fldFileToStr)(dr))]
.filter((pth) => Boolean(pth))
.map((pth) => lockPathFor(pth))
.sort();
yield acquireLocks(lockPaths);
try {
yield Promise.all(allCommandsArr.map((cmdArr) => {
return execPromise(cmdArr.join(" "));
}));
}
finally {
releaseLocks(lockPaths);
}
console.log(`${dirPath} Folder Sync Complete. Exiting ...`);
});
}