axiodb
Version:
The Pure JavaScript Alternative to SQLite. Embedded NoSQL database for Node.js with MongoDB-style queries, zero native dependencies, built-in InMemoryCache, and web GUI. Perfect for desktop apps, CLI tools, and embedded systems. No compilation, no platfor
151 lines • 6.97 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
/* eslint-disable @typescript-eslint/no-explicit-any */
const crypto_1 = require("crypto");
const FileManager_1 = __importDefault(require("../../engine/Filesystem/FileManager"));
const FolderManager_1 = __importDefault(require("../../engine/Filesystem/FolderManager"));
const Converter_helper_1 = __importDefault(require("../../Helper/Converter.helper"));
const response_helper_1 = __importDefault(require("../../Helper/response.helper"));
class LockManager {
constructor(collectionPath) {
this.maxWaitTime = 30000;
this.pollInterval = 100;
this.collectionPath = collectionPath;
this.lockDir = `${collectionPath}/.transactions/locks`;
this.FileManager = new FileManager_1.default();
this.FolderManager = new FolderManager_1.default();
this.Converter = new Converter_helper_1.default();
this.ResponseHelper = new response_helper_1.default();
}
acquireLock(documentId, transactionId, transactionTimestamp) {
return __awaiter(this, void 0, void 0, function* () {
try {
const dirExists = yield this.FolderManager.DirectoryExists(this.lockDir);
if (!dirExists.status) {
yield this.FolderManager.CreateDirectory(this.lockDir);
}
const lockFilePath = `${this.lockDir}/${documentId}.lock`;
const startTime = Date.now();
while (Date.now() - startTime < this.maxWaitTime) {
const fileExists = yield this.FileManager.FileExists(lockFilePath);
if (!fileExists.status) {
const lockInfo = {
documentId,
transactionId,
lockType: 'WRITE',
timestamp: transactionTimestamp,
};
const lockData = this.Converter.ToString(lockInfo);
const checksum = (0, crypto_1.createHash)('sha256').update(lockData).digest('hex');
const lockContent = this.Converter.ToString({ lockInfo, checksum });
const writeResult = yield this.FileManager.WriteFile(lockFilePath, lockContent);
if (writeResult.status) {
return this.ResponseHelper.Success({ message: "Lock acquired", documentId });
}
}
else {
const lockOwner = yield this.getLockOwner(documentId);
if (lockOwner) {
const ownerTimestamp = lockOwner.timestamp;
if (transactionTimestamp < ownerTimestamp) {
yield this.sleep(this.pollInterval);
continue;
}
else {
return this.ResponseHelper.Error(`Deadlock detected: Transaction ${transactionId} aborted (Wait-Die)`);
}
}
}
yield this.sleep(this.pollInterval);
}
return this.ResponseHelper.Error("Lock acquisition timeout");
}
catch (error) {
return this.ResponseHelper.Error(error);
}
});
}
releaseLock(documentId) {
return __awaiter(this, void 0, void 0, function* () {
try {
const lockFilePath = `${this.lockDir}/${documentId}.lock`;
const fileExists = yield this.FileManager.FileExists(lockFilePath);
if (fileExists.status) {
yield this.FileManager.DeleteFile(lockFilePath);
}
return this.ResponseHelper.Success({ message: "Lock released", documentId });
}
catch (error) {
return this.ResponseHelper.Error(error);
}
});
}
releaseAllLocks(documentIds) {
return __awaiter(this, void 0, void 0, function* () {
for (const documentId of documentIds) {
try {
yield this.releaseLock(documentId);
}
catch (error) {
continue;
}
}
});
}
isLocked(documentId) {
return __awaiter(this, void 0, void 0, function* () {
try {
const lockFilePath = `${this.lockDir}/${documentId}.lock`;
const fileExists = yield this.FileManager.FileExists(lockFilePath);
return fileExists.status;
}
catch (error) {
return false;
}
});
}
getLockOwner(documentId) {
return __awaiter(this, void 0, void 0, function* () {
try {
const lockFilePath = `${this.lockDir}/${documentId}.lock`;
const fileExists = yield this.FileManager.FileExists(lockFilePath);
if (!fileExists.status) {
return null;
}
const readResult = yield this.FileManager.ReadFile(lockFilePath);
if (!readResult.status) {
return null;
}
const lockData = this.Converter.ToObject(readResult.data);
const { lockInfo, checksum } = lockData;
const calculatedChecksum = (0, crypto_1.createHash)('sha256')
.update(this.Converter.ToString(lockInfo))
.digest('hex');
if (calculatedChecksum === checksum) {
return lockInfo;
}
return null;
}
catch (error) {
return null;
}
});
}
sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
}
exports.default = LockManager;
//# sourceMappingURL=LockManager.service.js.map