/// <summary> /// Try enter in shared lock (read) - Call action if request a new lock /// [Non ThreadSafe] /// </summary> private Action LockShared() { lock (_disk) { if (_state != LockState.Unlocked) { return () => { } } ; _disk.Lock(LockState.Shared, _timeout); _state = LockState.Shared; _shared = true; _log.Write(Logger.LOCK, "entered in shared lock mode"); this.AvoidDirtyRead(); return(() => { _shared = false; _disk.Unlock(LockState.Shared); _state = LockState.Unlocked; _log.Write(Logger.LOCK, "exited shared lock mode"); }); } }
/// <summary> /// Enter in Shared lock mode. /// </summary> public LockControl Read() { // if read or write if (_thread.IsReadLockHeld || _thread.IsWriteLockHeld) { return(new LockControl(false, () => { })); } // try enter in read mode if (!_thread.TryEnterReadLock(_timeout)) { throw LiteException.LockTimeout(_timeout); } _log.Write(Logger.LOCK, "entered in read lock mode in thread #{0}", this.ThreadId); // lock disk in shared mode var position = _disk.Lock(LockState.Read, _timeout); var changed = this.DetectDatabaseChanges(); return(new LockControl(changed, () => { // exit disk lock mode _disk.Unlock(LockState.Read, position); // exit thread lock mode _thread.ExitReadLock(); _log.Write(Logger.LOCK, "exited read lock mode in thread #{0}", this.ThreadId); })); }
/// <summary> /// Try enter in shared lock (read) - Call action if request a new lock /// </summary> public LockControl Shared(Action actionIfNewLock) { lock (_disk) { if (_state != LockState.Unlocked) { return(new LockControl(null)); } _log.Write(Logger.DISK, "enter in shared lock mode"); _disk.Lock(LockState.Shared); _state = LockState.Shared; _shared = true; actionIfNewLock(); return(new LockControl(() => { _log.Write(Logger.DISK, "exit shared lock mode"); _shared = false; _state = LockState.Unlocked; _disk.Unlock(LockState.Shared); })); } }
/// <summary> /// Initialize LiteEngine using custom disk service implementation and full engine options /// </summary> public LiteEngine(IDiskService disk, string password = null, TimeSpan?timeout = null, int cacheSize = 5000, Logger log = null, bool utcDate = false) { if (disk == null) { throw new ArgumentNullException("disk"); } _timeout = timeout ?? TimeSpan.FromMinutes(1); _cacheSize = cacheSize; _disk = disk; _log = log ?? new Logger(); _bsonReader = new BsonReader(utcDate); try { // initialize datafile (create) and set log instance _disk.Initialize(_log, password); // lock disk (read mode) before read header var position = _disk.Lock(LockState.Read, _timeout); var buffer = _disk.ReadPage(0); _disk.Unlock(LockState.Read, position); // create header instance from array bytes var header = BasePage.ReadPage(buffer) as HeaderPage; // hash password with sha1 or keep as empty byte[20] var sha1 = password == null ? new byte[20] : AesEncryption.HashSHA1(password); // compare header password with user password even if not passed password (datafile can have password) if (sha1.BinaryCompareTo(header.Password) != 0) { throw LiteException.DatabaseWrongPassword(); } // initialize AES encryptor if (password != null) { _crypto = new AesEncryption(password, header.Salt); } // initialize all services this.InitializeServices(); // if header are marked with recovery, do it now if (header.Recovery) { _trans.Recovery(); } } catch (Exception) { // explicit dispose this.Dispose(); throw; } }
/// <summary> /// Starts a new transaction - lock database to garantee that only one processes is in a transaction /// </summary> public void Begin() { if (_trans) { throw new Exception("Begin transaction already exists"); } // lock (or try to) datafile _disk.Lock(); _trans = true; }