UNPKG

cs-element

Version:

Advanced reactive data management library with state machines, blueprints, persistence, compression, networking, and multithreading support

702 lines (581 loc) 24.8 kB
# 🔒 Транзакции и блокировки CSElement предоставляет мощную систему транзакций с поддержкой ACID-свойств и управления блокировками для обеспечения целостности данных. ## 📋 Содержание - [Основы транзакций](#основы-транзакций) - [Система блокировок](#система-блокировок) - [Уровни изоляции](#уровни-изоляции) - [Точки сохранения](#точки-сохранения) - [Обнаружение взаимоблокировок](#обнаружение-взаимоблокировок) - [Полный пример](#полный-пример-банковская-система) ## Основы транзакций ### Создание и управление транзакциями ```typescript import { TransactionManagerImpl, LockManagerImpl, TransactionConfig, IsolationLevel, TransactionOperationType } from 'cs-element'; // Создание менеджеров const lockManager = new LockManagerImpl(); const transactionManager = new TransactionManagerImpl(lockManager); // Простая транзакция const transaction = await transactionManager.begin(); try { // Выполняем операции await transaction.addOperation({ id: 'op1', type: TransactionOperationType.UPDATE, elementId: 'user-123', timestamp: Date.now(), execute: async () => { // Обновляем данные пользователя const user = CSElement.getElementById('user-123'); await user.setData('balance', 1000); return 'success'; }, rollback: async () => { // Откат изменений const user = CSElement.getElementById('user-123'); await user.setData('balance', 500); } }); // Коммитим транзакцию await transaction.commit(); console.log('✅ Транзакция успешно завершена'); } catch (error) { // Откатываем при ошибке await transaction.rollback(); console.error('❌ Транзакция отменена:', error); } ``` ### Конфигурация транзакций ```typescript // Расширенная конфигурация const config: TransactionConfig = { isolationLevel: IsolationLevel.SERIALIZABLE, timeout: 30000, // 30 секунд maxOperations: 100, enableLogging: true, enableProfiling: true, autoCommit: false, readOnly: false }; const transaction = await transactionManager.begin(config); // Получение информации о транзакции const info = transaction.getInfo(); console.log('Информация о транзакции:', { id: info.id, status: info.status, operationsCount: info.operationsCount, duration: info.duration, isolationLevel: info.isolationLevel }); ``` ### Функциональный подход ```typescript // Выполнение операций в контексте транзакции const result = await transactionManager.withTransaction(async (tx) => { // Операция 1: Списание с одного счета await tx.addOperation({ id: 'debit', type: TransactionOperationType.UPDATE, elementId: 'account-from', execute: async () => { const account = CSElement.getElementById('account-from'); const balance = await account.getData('balance') as number; if (balance < 100) { throw new Error('Недостаточно средств'); } await account.setData('balance', balance - 100); return balance - 100; }, rollback: async () => { const account = CSElement.getElementById('account-from'); const balance = await account.getData('balance') as number; await account.setData('balance', balance + 100); } }); // Операция 2: Зачисление на другой счет await tx.addOperation({ id: 'credit', type: TransactionOperationType.UPDATE, elementId: 'account-to', execute: async () => { const account = CSElement.getElementById('account-to'); const balance = await account.getData('balance') as number; await account.setData('balance', balance + 100); return balance + 100; }, rollback: async () => { const account = CSElement.getElementById('account-to'); const balance = await account.getData('balance') as number; await account.setData('balance', balance - 100); } }); return 'Перевод выполнен успешно'; }, { isolationLevel: IsolationLevel.SERIALIZABLE, timeout: 15000 }); console.log('Результат:', result); ``` ## Система блокировок ### Типы блокировок ```typescript // Read-блокировка (разделяемая) const readLockAcquired = await lockManager.acquireLock( 'element-123', 'transaction-1', 'read' ); // Write-блокировка (эксклюзивная) const writeLockAcquired = await lockManager.acquireLock( 'element-123', 'transaction-2', 'write' ); // Проверка блокировки const isLocked = lockManager.isLocked('element-123'); console.log('Элемент заблокирован:', isLocked); // Информация о блокировке const lockInfo = lockManager.getLockInfo('element-123'); console.log('Информация о блокировке:', { locked: lockInfo.locked, lockType: lockInfo.lockType, transactionId: lockInfo.transactionId, acquiredAt: lockInfo.acquiredAt, waitingRequests: lockInfo.waitingRequests }); ``` ### Управление блокировками ```typescript class SmartLockManager { private lockManager: LockManagerImpl; private lockTimeouts: Map<string, NodeJS.Timeout> = new Map(); constructor(lockManager: LockManagerImpl) { this.lockManager = lockManager; } async acquireLockWithTimeout( elementId: string, transactionId: string, lockType: 'read' | 'write', timeoutMs: number = 5000 ): Promise<boolean> { return new Promise((resolve, reject) => { const timeout = setTimeout(() => { reject(new Error(`Таймаут получения блокировки для ${elementId}`)); }, timeoutMs); this.lockManager.acquireLock(elementId, transactionId, lockType) .then(acquired => { clearTimeout(timeout); if (acquired) { this.lockTimeouts.set(`${elementId}-${transactionId}`, timeout); } resolve(acquired); }) .catch(error => { clearTimeout(timeout); reject(error); }); }); } async releaseLockSafely(elementId: string, transactionId: string): Promise<boolean> { const key = `${elementId}-${transactionId}`; const timeout = this.lockTimeouts.get(key); if (timeout) { clearTimeout(timeout); this.lockTimeouts.delete(key); } return await this.lockManager.releaseLock(elementId, transactionId); } async releaseAllLocksForTransaction(transactionId: string): Promise<number> { // Очищаем все таймауты для транзакции for (const [key, timeout] of this.lockTimeouts) { if (key.endsWith(`-${transactionId}`)) { clearTimeout(timeout); this.lockTimeouts.delete(key); } } return await this.lockManager.releaseAllLocks(transactionId); } } ``` ## Уровни изоляции ### READ_UNCOMMITTED ```typescript // Самый низкий уровень изоляции const transaction = await transactionManager.begin({ isolationLevel: IsolationLevel.READ_UNCOMMITTED }); // Может читать незафиксированные изменения других транзакций // Возможны грязные чтения, неповторяемые чтения, фантомные чтения ``` ### READ_COMMITTED ```typescript // Предотвращает грязные чтения const transaction = await transactionManager.begin({ isolationLevel: IsolationLevel.READ_COMMITTED }); // Читает только зафиксированные данные // Возможны неповторяемые чтения и фантомные чтения ``` ### REPEATABLE_READ ```typescript // Предотвращает грязные и неповторяемые чтения const transaction = await transactionManager.begin({ isolationLevel: IsolationLevel.REPEATABLE_READ }); // Гарантирует, что повторное чтение вернет те же данные // Возможны фантомные чтения ``` ### SERIALIZABLE ```typescript // Самый высокий уровень изоляции const transaction = await transactionManager.begin({ isolationLevel: IsolationLevel.SERIALIZABLE }); // Полная изоляция, как будто транзакции выполняются последовательно // Предотвращает все аномалии чтения ``` ## Точки сохранения ### Создание и использование ```typescript const transaction = await transactionManager.begin(); try { // Выполняем первую группу операций await transaction.addOperation({ id: 'op1', type: TransactionOperationType.CREATE, elementId: 'new-user', execute: async () => { const user = new CSElement('new-user'); await user.setData('name', 'John Doe'); return 'user created'; }, rollback: async () => { // Удаляем созданного пользователя CSElement.removeElement('new-user'); } }); // Создаем точку сохранения const savepoint1 = await transaction.createSavepoint('after-user-creation'); console.log('✅ Точка сохранения создана:', savepoint1.name); // Выполняем вторую группу операций await transaction.addOperation({ id: 'op2', type: TransactionOperationType.UPDATE, elementId: 'new-user', execute: async () => { const user = CSElement.getElementById('new-user'); await user.setData('email', 'invalid-email'); // Некорректный email return 'email set'; }, rollback: async () => { const user = CSElement.getElementById('new-user'); await user.deleteData('email'); } }); // Валидация email const user = CSElement.getElementById('new-user'); const email = await user.getData('email') as string; if (!email.includes('@')) { // Откатываемся к точке сохранения await transaction.rollbackToSavepoint(savepoint1.id); console.log('🔄 Откат к точке сохранения после ошибки валидации'); // Исправляем email await transaction.addOperation({ id: 'op2-fixed', type: TransactionOperationType.UPDATE, elementId: 'new-user', execute: async () => { const user = CSElement.getElementById('new-user'); await user.setData('email', 'john.doe@example.com'); return 'email corrected'; }, rollback: async () => { const user = CSElement.getElementById('new-user'); await user.deleteData('email'); } }); } await transaction.commit(); console.log('✅ Транзакция успешно завершена'); } catch (error) { await transaction.rollback(); console.error('❌ Транзакция отменена:', error); } ``` ### Управление точками сохранения ```typescript class SavepointManager { private transaction: Transaction; private savepoints: Map<string, Savepoint> = new Map(); constructor(transaction: Transaction) { this.transaction = transaction; } async createNamedSavepoint(name: string): Promise<Savepoint> { const savepoint = await this.transaction.createSavepoint(name); this.savepoints.set(name, savepoint); return savepoint; } async rollbackToNamed(name: string): Promise<void> { const savepoint = this.savepoints.get(name); if (!savepoint) { throw new Error(`Точка сохранения '${name}' не найдена`); } await this.transaction.rollbackToSavepoint(savepoint.id); // Удаляем все точки сохранения после данной for (const [spName, sp] of this.savepoints) { if (sp.timestamp > savepoint.timestamp) { this.savepoints.delete(spName); } } } async releaseNamed(name: string): Promise<void> { const savepoint = this.savepoints.get(name); if (savepoint) { await this.transaction.releaseSavepoint(savepoint.id); this.savepoints.delete(name); } } listSavepoints(): Array<{ name: string; timestamp: number }> { return Array.from(this.savepoints.entries()).map(([name, sp]) => ({ name, timestamp: sp.timestamp })); } } ``` ## Обнаружение взаимоблокировок ```typescript class DeadlockDetector { private lockManager: LockManagerImpl; private detectionInterval: NodeJS.Timeout; constructor(lockManager: LockManagerImpl, intervalMs: number = 5000) { this.lockManager = lockManager; this.detectionInterval = setInterval(() => { this.detectAndResolveDeadlocks(); }, intervalMs); } private async detectAndResolveDeadlocks(): Promise<void> { const deadlocks = this.lockManager.detectDeadlocks(); if (deadlocks.length > 0) { console.warn(`🚨 Обнаружено ${deadlocks.length} взаимоблокировок`); for (const deadlock of deadlocks) { await this.resolveDeadlock(deadlock); } } } private async resolveDeadlock(deadlock: any): Promise<void> { // Стратегия: отменяем транзакцию с наименьшим приоритетом const transactionsInDeadlock = deadlock.transactions; // Сортируем по времени начала (младшие транзакции имеют приоритет) transactionsInDeadlock.sort((a: any, b: any) => b.startTime - a.startTime); const victimTransaction = transactionsInDeadlock[0]; console.log(`🎯 Выбрана жертва взаимоблокировки: ${victimTransaction.id}`); // Принудительно откатываем транзакцию try { await victimTransaction.rollback(); console.log(`✅ Транзакция ${victimTransaction.id} отменена для разрешения взаимоблокировки`); } catch (error) { console.error(`❌ Ошибка отмены транзакции ${victimTransaction.id}:`, error); } } destroy(): void { if (this.detectionInterval) { clearInterval(this.detectionInterval); } } } ``` ## Полный пример: Банковская система ```typescript class BankingSystem { private transactionManager: TransactionManagerImpl; private lockManager: LockManagerImpl; private deadlockDetector: DeadlockDetector; private accounts: Map<string, CSElement> = new Map(); constructor() { this.lockManager = new LockManagerImpl(); this.transactionManager = new TransactionManagerImpl(this.lockManager); this.deadlockDetector = new DeadlockDetector(this.lockManager); } async createAccount(accountId: string, initialBalance: number): Promise<void> { const account = new CSElement(accountId); await account.setData('balance', initialBalance); await account.setData('created', new Date().toISOString()); await account.setData('transactions', []); this.accounts.set(accountId, account); console.log(`🏦 Счет ${accountId} создан с балансом ${initialBalance}`); } async transfer( fromAccountId: string, toAccountId: string, amount: number, description: string = 'Перевод' ): Promise<string> { return await this.transactionManager.withTransaction(async (tx) => { const transferId = `transfer-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; // Операция 1: Проверка и списание средств await tx.addOperation({ id: `${transferId}-debit`, type: TransactionOperationType.UPDATE, elementId: fromAccountId, execute: async () => { const fromAccount = this.accounts.get(fromAccountId); if (!fromAccount) { throw new Error(`Счет ${fromAccountId} не найден`); } const balance = await fromAccount.getData('balance') as number; if (balance < amount) { throw new Error(`Недостаточно средств. Баланс: ${balance}, требуется: ${amount}`); } await fromAccount.setData('balance', balance - amount); // Добавляем запись о транзакции const transactions = await fromAccount.getData('transactions') as any[]; transactions.push({ id: transferId, type: 'debit', amount: -amount, description, timestamp: new Date().toISOString(), relatedAccount: toAccountId }); await fromAccount.setData('transactions', transactions); return balance - amount; }, rollback: async () => { const fromAccount = this.accounts.get(fromAccountId); if (fromAccount) { const balance = await fromAccount.getData('balance') as number; await fromAccount.setData('balance', balance + amount); // Удаляем запись о транзакции const transactions = await fromAccount.getData('transactions') as any[]; const filteredTransactions = transactions.filter(t => t.id !== transferId); await fromAccount.setData('transactions', filteredTransactions); } } }); // Точка сохранения после списания const debitSavepoint = await tx.createSavepoint('after-debit'); // Операция 2: Зачисление средств await tx.addOperation({ id: `${transferId}-credit`, type: TransactionOperationType.UPDATE, elementId: toAccountId, execute: async () => { const toAccount = this.accounts.get(toAccountId); if (!toAccount) { throw new Error(`Счет ${toAccountId} не найден`); } const balance = await toAccount.getData('balance') as number; await toAccount.setData('balance', balance + amount); // Добавляем запись о транзакции const transactions = await toAccount.getData('transactions') as any[]; transactions.push({ id: transferId, type: 'credit', amount: amount, description, timestamp: new Date().toISOString(), relatedAccount: fromAccountId }); await toAccount.setData('transactions', transactions); return balance + amount; }, rollback: async () => { const toAccount = this.accounts.get(toAccountId); if (toAccount) { const balance = await toAccount.getData('balance') as number; await toAccount.setData('balance', balance - amount); // Удаляем запись о транзакции const transactions = await toAccount.getData('transactions') as any[]; const filteredTransactions = transactions.filter(t => t.id !== transferId); await toAccount.setData('transactions', filteredTransactions); } } }); console.log(`💸 Перевод ${amount} с ${fromAccountId} на ${toAccountId} выполнен`); return transferId; }, { isolationLevel: IsolationLevel.SERIALIZABLE, timeout: 30000, enableLogging: true }); } async getBalance(accountId: string): Promise<number> { const account = this.accounts.get(accountId); if (!account) { throw new Error(`Счет ${accountId} не найден`); } return await account.getData('balance') as number; } async getTransactionHistory(accountId: string): Promise<any[]> { const account = this.accounts.get(accountId); if (!account) { throw new Error(`Счет ${accountId} не найден`); } return await account.getData('transactions') as any[]; } async getSystemStats(): Promise<any> { const lockStats = this.lockManager.getStats(); const transactionStats = this.transactionManager.getStats(); return { accounts: this.accounts.size, locks: lockStats, transactions: transactionStats, totalBalance: Array.from(this.accounts.values()).reduce(async (sum, account) => { const balance = await account.getData('balance') as number; return await sum + balance; }, Promise.resolve(0)) }; } destroy(): void { this.deadlockDetector.destroy(); this.transactionManager.destroy(); this.lockManager.destroy(); } } // Демонстрация использования async function demonstrateBankingSystem() { const bank = new BankingSystem(); try { // Создаем счета await bank.createAccount('acc-001', 1000); await bank.createAccount('acc-002', 500); await bank.createAccount('acc-003', 750); console.log('📊 Начальные балансы:'); console.log('acc-001:', await bank.getBalance('acc-001')); console.log('acc-002:', await bank.getBalance('acc-002')); console.log('acc-003:', await bank.getBalance('acc-003')); // Выполняем переводы const transfer1 = await bank.transfer('acc-001', 'acc-002', 200, 'Оплата услуг'); const transfer2 = await bank.transfer('acc-002', 'acc-003', 150, 'Возврат долга'); console.log('💰 Переводы выполнены:', transfer1, transfer2); console.log('📊 Конечные балансы:'); console.log('acc-001:', await bank.getBalance('acc-001')); console.log('acc-002:', await bank.getBalance('acc-002')); console.log('acc-003:', await bank.getBalance('acc-003')); // История транзакций console.log('📋 История acc-001:', await bank.getTransactionHistory('acc-001')); // Статистика системы console.log('📈 Статистика системы:', await bank.getSystemStats()); } catch (error) { console.error('❌ Ошибка в банковской системе:', error); } finally { bank.destroy(); } } demonstrateBankingSystem().catch(console.error); ``` ## 🎯 Заключение Система транзакций и блокировок CSElement обеспечивает: - **🔒 ACID-свойства** - атомарность, согласованность, изоляция, долговечность - **⚡ Производительность** - оптимизированное управление блокировками - **🛡️ Надёжность** - обнаружение и разрешение взаимоблокировок - **🎯 Гибкость** - различные уровни изоляции и точки сохранения - **📊 Мониторинг** - подробная статистика и логирование --- **Следующий раздел:** [Персистентность и адаптеры →](10-persistence-and-adapters.md)