Ejemplo n.º 1
0
        private void TXN_BEGIN(string dbName, string tableName = null, object recordKey = null, bool block = false)
        {
            logger.Debug("TXN_BEGIN");

            // PURPOSE:
            // Create a lock
            // Open/prepare shared datastore for all the future modify functions

            // verify block transaction status
            if (block && !blockTxn)
            {
                blockTxn = block;
            }

            // validate input
            // db might be null
            // make sure db is specified when locking a table
            if (tableName != null && dbName is null)
            {
                throw new Exception("DB must be specified when opening a table-level transaction.");
            }
            // make sure db:table is specified when locking a record
            if (recordKey != null && (tableName is null || dbName is null))
            {
                throw new Exception("DB and Table must be specified when opening a record-level transaction.");
            }

            // write the lock
            ConnectionLock newLock = new ConnectionLock(ConnectionSource, ConnectionRequester, ConnectionId, dbName, tableName, recordKey);

            if (activeConnLock != null)
            {
                logger.Debug("Active lock exists: {0}", activeConnLock);
                ConnectionLock txnLock = DetermineHigherLock(activeConnLock, newLock);
                if (txnLock != activeConnLock)
                {
                    activeConnLock = AcquireLocks(newLock);
                }
                logger.Debug("Using lock: {0}", activeConnLock);
            }
            else
            {
                activeConnLock = AcquireLocks(newLock);
            }

            // if no active datastore (means that this is the first BEGIN in a txn chain,
            // then set the active datastore
            if (activeDStore is null)
            {
                activeDStore = new DataStore(ActiveDataStoreType);
            }
        }
Ejemplo n.º 2
0
        private void TXN_END(bool block = false)
        {
            logger.Debug("TXN_END");

            // close the block if block is true (called by END)
            // if block is false, the TXN_END is being called from commands
            if (block)
            {
                blockTxn = false;
            }

            // if there is no active block txn, close and commit
            // otherwise skip writing changes until END block is requested
            if (!blockTxn)
            {
                // close only if there is an active dstore
                if (activeDStore != null)
                {
                    try {
                        // now close and commit the datastore
                        activeDStore.Commit();
                        activeDStore.Dispose();
                        activeDStore = null;
                    }
                    catch (Exception commitEx) {
                        throw new Exception(
                                  string.Format("Exception occured while trying to commit changes. | {0}",
                                                commitEx.Message));
                    }
                    finally {
                        // drop all new locks created by this connection
                        ReleaseLocks();
                        activeConnLock = null;
                    }
                }
            }
        }
Ejemplo n.º 3
0
        private ConnectionLock DetermineHigherLock(ConnectionLock exstLock, ConnectionLock newLock)
        {
            ConnectionLock txnLock = newLock;

            // is existing lock restricting access?
            if (newLock.IsRestrictedBy(exstLock))
            {
                //  does restricting lock belong to this connection?
                //  if yes and it is a higher-level lock, use that
                if (exstLock.BelongsTo(this) && exstLock.LockType <= newLock.LockType)
                {
                    logger.Debug("Existing lock {0} is higher than new {1}", exstLock, newLock);
                    txnLock = exstLock;
                }
                //  does the lock not belong to this connection in which case reject
                //  or is trying to acquire a higher level lock that active lock
                else
                {
                    logger.Debug("New lock {0} is restricted by {1}", newLock, exstLock);
                    throw new AccessRestrictedException(newLock, exstLock);
                }
            }
            // if not restricting, does this connection already have a txn block lock of equal level
            // reject again since the connection need to close its block lock first and then
            // work on another entry
            else
            {
                if (exstLock.BelongsTo(this))
                {
                    logger.Debug("New lock {0} not on the same path as existing {1}", newLock, exstLock);
                    throw new AccessRestrictedByExistingLockException(newLock, exstLock);
                }
            }

            return(txnLock);
        }
Ejemplo n.º 4
0
        private ConnectionLock AcquireLocks(ConnectionLock newLock)
        {
            logger.Debug("RECORD LOCK");

            ConnectionLock txnLock = newLock;

            // open datastore for exclusive access
            using (var dstore = new DataStore(ActiveDataStoreType, exclusive: true)) {
                // get all existing locks
                // check access, find the highest-level compatible lock
                logger.Debug("Reading existing locks");
                foreach (ConnectionLock activeLock in ReadActiveLocks(dstore))
                {
                    logger.Debug("Lock Found: {0}", activeLock);
                    txnLock = DetermineHigherLock(activeLock, newLock);
                }

                logger.Debug("Using lock: {0}", txnLock);
                // at this point, the are no locks that restrict access
                // but we might be re-using an active compatible lock
                // so only write the lock if is not existing compatible
                if (txnLock == newLock)
                {
                    try {
                        // register the new lock: if target is not locked, lock it
                        DataFunctions.InsertRecord(
                            dstore,
                            connDbName,
                            connDbLocksTableName,
                            newLock.LockId,
                            new Dictionary <string, object>()
                        {
                            { connDbLockSourceField, newLock.LockSource },
                            { connDbLockRequesterField, newLock.LockRequester },
                            { connDbLockConnUUIDField, newLock.LockConnId },
                            { connDbLockDBField, newLock.LockTargetDB },
                            { connDbLockTableField, newLock.LockTargetTable },
                            { connDbLockRecordKeyField, newLock.LockTargetRecordKey },
                        });
                    }
                    catch (Exception lockEx) {
                        // finally statement closes the dstore and release the exclusivity if throwing an exception
                        throw new Exception(
                                  string.Format("Error creating lock: {0} | {1}", newLock, lockEx.Message)
                                  );
                    }
                    finally {
                        try {
                            // write changes
                            dstore.Commit();
                        }
                        catch (Exception commitEx) {
                            // finally statement closes the dstore and release the exclusivity if throwing an exception
                            throw new Exception(
                                      string.Format("Exception occured when commiting new locks. | {0}", commitEx.Message)
                                      );
                        }
                    }
                }
            }

            return(txnLock);
        }
Ejemplo n.º 5
0
 public void END(ConnectionLock cLock = null)
 {
     // user ends a transaction block
     TXN_END(block: true);
 }
Ejemplo n.º 6
0
        public bool IsRestrictedBy(ConnectionLock otherLock)
        {
            // this method checks two-way locking conflicts
            // db:table conflicts with db:table:record both ways.
            // because if a connection has a lock on db:table:record, another connection should not
            // be able to lock its parent db:table
            // also if a connection has a lock on db:table, another connection should not
            // be able to lock its child db:table:record

            // checking for master datastore locks first
            // if any lock is a datastore lock, all other locks are in conflict
            if (IsDataStoreLock || otherLock.IsDataStoreLock)
            {
                logger.Debug("At least one lock is a datastore lock.");
                return(true);
            }

            // checking db:table:record locks
            if (LockType == otherLock.LockType)
            {
                logger.Debug("Lock types are equal = {0}", LockType);
                // if lock types are equal
                // check if we have equal lock targets
                switch (LockType)
                {
                case ConnectionLockType.DB:
                    if (otherLock.LockTargetDB == LockTargetDB)
                    {
                        return(true);
                    }
                    break;

                case ConnectionLockType.Table:
                    if (otherLock.LockTargetDB == LockTargetDB &&
                        otherLock.LockTargetTable == LockTargetTable)
                    {
                        return(true);
                    }
                    break;

                case ConnectionLockType.Record:
                    if (otherLock.LockTargetDB == LockTargetDB &&
                        otherLock.LockTargetTable == LockTargetTable &&
                        otherLock.LockTargetRecordKey.Equals(LockTargetRecordKey))
                    {
                        return(true);
                    }
                    break;
                }
            }
            else if (LockType < otherLock.LockType)
            {
                logger.Debug("This lock is higher-level than other.");
                // if I have a higher-degree lock, test if I'm holding a lock on other lock targets
                if (LockType == ConnectionLockType.DB)
                {
                    // Am I trying to lock other locks target db?
                    if (otherLock.LockTargetDB == LockTargetDB)
                    {
                        logger.Debug("This lock is locking other locks DB.");
                        return(true);
                    }
                }
                else if (LockType == ConnectionLockType.Table)
                {
                    // Am I trying to lock other locks target db:table?
                    if (otherLock.LockTargetDB == LockTargetDB &&
                        otherLock.LockTargetTable == LockTargetTable)
                    {
                        logger.Debug("This lock is locking other locks DB:Table.");
                        return(true);
                    }
                }
                // there is nothing lower than the record lock and I'm higher-degree than other lock
                // so I'm definitely not record otherwise we would have been equal
            }
            else
            {
                logger.Debug("This lock is lower-level than other.");
                // if no condition above is met, then LockType > otherLock.LockType
                // if I have a lower-degree lock, test if other lock is trying to lock my targets
                if (otherLock.LockType == ConnectionLockType.DB)
                {
                    // Is other lock trying to lock the db containing my table?
                    if (otherLock.LockTargetDB == LockTargetDB)
                    {
                        logger.Debug("Other lock is locking this locks DB.");
                        return(true);
                    }
                }
                else if (otherLock.LockType == ConnectionLockType.Table)
                {
                    // Is other lock trying to lock the db containing my table?
                    if (otherLock.LockTargetDB == LockTargetDB &&
                        otherLock.LockTargetTable == LockTargetTable)
                    {
                        logger.Debug("Other lock is locking this locks DB:Table.");
                        return(true);
                    }
                }
                // there is nothing lower than the record lock and otherLock is higher-degree than me
                // so otherLock is definitely not record otherwise we would have been equal
            }

            return(false);
        }
Ejemplo n.º 7
0
 public bool IsIdenticalTo(ConnectionLock connLock)
 {
     return(connLock.LockId == LockId &&
            connLock.LockConnectionSignature == LockConnectionSignature &&
            connLock.LockHierarchy == LockHierarchy);
 }
Ejemplo n.º 8
0
        private void AcquireLocks(ConnectionLock newLock)
        {
            logger.Debug("RECORD LOCK");

            // open datastore for exclusive access
            using (var dstore = new DataStore(ActiveDataStoreType, exclusive: true)) {
                // get all existing locks
                // check access, find the highest-level compatible lock
                ConnectionLock txnLock = newLock;
                foreach (ConnectionLock activeLock in ReadActiveLocks(dstore))
                {
                    logger.Debug("Lock Found: {0}", activeLock);
                    // is existing lock restricting access?
                    if (newLock.IsRestrictedBy(activeLock))
                    {
                        //  does restricting lock belong to this connection?
                        //  if yes and it is a higher-level lock, use that
                        if (activeLock.BelongsTo(this) && activeLock.LockType <= newLock.LockType)
                        {
                            logger.Debug("Existing lock {0} is higher than new {1}", activeLock, newLock);
                            txnLock = activeLock;
                        }
                        //  does the lock not belong to this connection in which case reject
                        //  or is trying to acquire a higher level lock that active lock
                        else
                        {
                            logger.Debug("New lock {0} is restricted by {1}", newLock, activeLock);
                            throw new AccessRestrictedException(newLock, activeLock);
                        }
                    }
                    // if not restricting, does this connection already have a txn block lock of equal level
                    // reject again since the connection need to close its block lock first and then
                    // work on another entry
                    else
                    {
                        if (activeLock.BelongsTo(this))
                        {
                            logger.Debug("New lock {0} not on the same path as existing {1}", newLock, activeLock);
                            throw new AccessRestrictedByExistingLockException(newLock, activeLock);
                        }
                    }
                }

                logger.Debug("Using lock: {0}", txnLock);
                // at this point, the are no locks that restrict access
                // but we might be re-using an active compatible lock
                // so only write the lock if is not existing compatible
                if (txnLock == newLock)
                {
                    try {
                        // register the new lock: if target is not locked, lock it
                        DataFunctions.InsertRecord(
                            dstore,
                            connDbName,
                            connDbLocksTableName,
                            newLock.LockId,
                            new Dictionary <string, object>()
                        {
                            { connDbLockSourceField, newLock.LockSource },
                            { connDbLockRequesterField, newLock.LockRequester },
                            { connDbLockConnUUIDField, newLock.LockConnId },
                            { connDbLockDBField, newLock.LockTargetDB },
                            { connDbLockTableField, newLock.LockTargetTable },
                            { connDbLockRecordKeyField, newLock.LockTargetRecordKey },
                        });
                    }
                    catch (Exception lockEx) {
                        // finally statement closes the dstore and release the exclusivity if throwing an exception
                        throw new Exception(
                                  string.Format("Error creating lock: {0} | {1}", newLock, lockEx.Message)
                                  );
                    }
                    finally {
                        try {
                            // write changes
                            dstore.Commit();
                        }
                        catch (Exception commitEx) {
                            // finally statement closes the dstore and release the exclusivity if throwing an exception
                            throw new Exception(
                                      string.Format("Exception occured when commiting new locks. | {0}", commitEx.Message)
                                      );
                        }
                    }
                }
            }
        }
Ejemplo n.º 9
0
 public AccessRestrictedByExistingLockException(ConnectionLock newLock, ConnectionLock restrictingLock)
 {
     NewLock         = newLock;
     RestrictingLock = restrictingLock;
 }