Esempio n. 1
0
 internal bool hasSharedCacheTableLock(Pgno rootID, bool isIndex, LOCK eLockType)
 {
     // If this database is not shareable, or if the client is reading and has the read-uncommitted flag set, then no lock is required.  Return true immediately.
     if (!Sharable || (eLockType == LOCK.READ && (DB.flags & sqlite3b.SQLITE.ReadUncommitted) != 0))
         return true;
     // If the client is reading or writing an index and the schema is not loaded, then it is too difficult to actually check to see if
     // the correct locks are held.  So do not bother - just return true. This case does not come up very often anyhow.
     var schema = Shared.Schema;
     if (isIndex && (schema == null || (schema.flags & SchemaFlags.SchemaLoaded) == 0))
         return true;
     // Figure out the root-page that the lock should be held on. For table b-trees, this is just the root page of the b-tree being read or
     // written. For index b-trees, it is the root page of the associated table.
     Pgno tableID = 0;
     if (isIndex)
         throw new NotImplementedException();
         //for (var p = schema.idxHash.first; p != null; p = p.next)
         //{
         //    var pIdx = (IIndex)p.data;
         //    if (pIdx.tnum == (int)rootID)
         //        tableID = pIdx.pTable.tnum;
         //}
     else
         tableID = rootID;
     // Search for the required lock. Either a write-lock on root-page iTab, a write-lock on the schema table, or (if the client is reading) a
     // read-lock on tableID will suffice. Return 1 if any of these are found.
     for (var @lock = Shared.Locks; @lock != null; @lock = @lock.Next)
         if (@lock.Tree == this && (@lock.TableID == tableID || (@lock.Lock == LOCK.WRITE && @lock.TableID == 1)) && @lock.Lock >= eLockType)
             return true;
     // Failed to find the required lock.
     return false;
 }
Esempio n. 2
0
        internal bool hasSharedCacheTableLock(Pgno rootID, bool isIndex, LOCK eLockType)
        {
            // If this database is not shareable, or if the client is reading and has the read-uncommitted flag set, then no lock is required.  Return true immediately.
            if (!Sharable || (eLockType == LOCK.READ && (DB.flags & sqlite3b.SQLITE.ReadUncommitted) != 0))
            {
                return(true);
            }
            // If the client is reading or writing an index and the schema is not loaded, then it is too difficult to actually check to see if
            // the correct locks are held.  So do not bother - just return true. This case does not come up very often anyhow.
            var schema = Shared.Schema;

            if (isIndex && (schema == null || (schema.flags & SchemaFlags.SchemaLoaded) == 0))
            {
                return(true);
            }
            // Figure out the root-page that the lock should be held on. For table b-trees, this is just the root page of the b-tree being read or
            // written. For index b-trees, it is the root page of the associated table.
            Pgno tableID = 0;

            if (isIndex)
            {
                throw new NotImplementedException();
            }
            //for (var p = schema.idxHash.first; p != null; p = p.next)
            //{
            //    var pIdx = (IIndex)p.data;
            //    if (pIdx.tnum == (int)rootID)
            //        tableID = pIdx.pTable.tnum;
            //}
            else
            {
                tableID = rootID;
            }
            // Search for the required lock. Either a write-lock on root-page iTab, a write-lock on the schema table, or (if the client is reading) a
            // read-lock on tableID will suffice. Return 1 if any of these are found.
            for (var @lock = Shared.Locks; @lock != null; @lock = @lock.Next)
            {
                if (@lock.Tree == this && (@lock.TableID == tableID || (@lock.Lock == LOCK.WRITE && @lock.TableID == 1)) && @lock.Lock >= eLockType)
                {
                    return(true);
                }
            }
            // Failed to find the required lock.
            return(false);
        }
Esempio n. 3
0
        internal RC querySharedCacheTableLock(Pgno tableID, LOCK eLock)
        {
            Debug.Assert(sqlite3BtreeHoldsMutex());
            Debug.Assert(eLock == LOCK.READ || eLock == LOCK.WRITE);
            Debug.Assert(DB != null);
            Debug.Assert((DB.flags & sqlite3b.SQLITE.ReadUncommitted) == 0 || eLock == LOCK.WRITE || tableID == 1);
            // If requesting a write-lock, then the Btree must have an open write transaction on this file. And, obviously, for this to be so there
            // must be an open write transaction on the file itself.
            var shared = this.Shared;

            Debug.Assert(eLock == LOCK.READ || (shared.Writer == this && InTransaction == TRANS.WRITE));
            Debug.Assert(eLock == LOCK.READ || shared.InTransaction == TRANS.WRITE);
            // This routine is a no-op if the shared-cache is not enabled
            if (!Sharable)
            {
                return(RC.OK);
            }
            // If some other connection is holding an exclusive lock, the requested lock may not be obtained.
            if (shared.Writer != this && shared.IsExclusive)
            {
                sqlite3b.sqlite3ConnectionBlocked(DB, shared.Writer.DB);
                return(RC.LOCKED_SHAREDCACHE);
            }
            for (var @lock = shared.Locks; @lock != null; @lock = @lock.Next)
            {
                // The condition (pIter.eLock!=eLock) in the following if(...) statement is a simplification of:
                //   (eLock==WRITE_LOCK || pIter.eLock==WRITE_LOCK)
                // since we know that if eLock==WRITE_LOCK, then no other connection may hold a WRITE_LOCK on any table in this file (since there can
                // only be a single writer).
                Debug.Assert(@lock.Lock == LOCK.READ || @lock.Lock == LOCK.WRITE);
                Debug.Assert(eLock == LOCK.READ || @lock.Tree == this || @lock.Lock == LOCK.READ);
                if (@lock.Tree != this && @lock.TableID == tableID && @lock.Lock != eLock)
                {
                    sqlite3b.sqlite3ConnectionBlocked(DB, @lock.Tree.DB);
                    if (eLock == LOCK.WRITE)
                    {
                        Debug.Assert(shared.Writer == this);
                        shared.IsPending = true;
                    }
                    return(RC.LOCKED_SHAREDCACHE);
                }
            }
            return(RC.OK);
        }
Esempio n. 4
0
        internal RC setSharedCacheTableLock(Pgno tableID, LOCK eLock)
        {
            Debug.Assert(sqlite3BtreeHoldsMutex());
            Debug.Assert(eLock == LOCK.READ || eLock == LOCK.WRITE);
            Debug.Assert(DB != null);
            // A connection with the read-uncommitted flag set will never try to obtain a read-lock using this function. The only read-lock obtained
            // by a connection in read-uncommitted mode is on the sqlite_master table, and that lock is obtained in BtreeBeginTrans().
            Debug.Assert((DB.flags & sqlite3b.SQLITE.ReadUncommitted) == 0 || eLock == LOCK.WRITE);
            // This function should only be called on a sharable b-tree after it has been determined that no other b-tree holds a conflicting lock.
            Debug.Assert(Sharable);
            Debug.Assert(querySharedCacheTableLock(tableID, eLock) == RC.OK);
            // First search the list for an existing lock on this table.
            BtreeLock pLock = null;

            for (var @lock = Shared.Locks; @lock != null; @lock = @lock.Next)
            {
                if (@lock.TableID == tableID && @lock.Tree == this)
                {
                    pLock = @lock;
                    break;
                }
            }
            // If the above search did not find a BtLock struct associating Btree p with table iTable, allocate one and link it into the list.
            if (pLock == null)
            {
                var shared = Shared;
                pLock         = new BtreeLock();
                pLock.TableID = tableID;
                pLock.Tree    = this;
                pLock.Next    = shared.Locks;
                shared.Locks  = pLock;
            }
            // Set the BtLock.eLock variable to the maximum of the current lock and the requested lock. This means if a write-lock was already held
            // and a read-lock requested, we don't incorrectly downgrade the lock.
            Debug.Assert(LOCK.WRITE > LOCK.READ);
            if (eLock > pLock.Lock)
            {
                pLock.Lock = eLock;
            }
            return(RC.OK);
        }
Esempio n. 5
0
 internal bool hasSharedCacheTableLock(Pgno b, bool c, LOCK d)
 {
     return(true);
 }
Esempio n. 6
0
 internal bool hasSharedCacheTableLock(Pgno b, bool c, LOCK d)
 {
     return true;
 }
Esempio n. 7
0
 internal RC setSharedCacheTableLock(Pgno tableID, LOCK eLock)
 {
     Debug.Assert(sqlite3BtreeHoldsMutex());
     Debug.Assert(eLock == LOCK.READ || eLock == LOCK.WRITE);
     Debug.Assert(DB != null);
     // A connection with the read-uncommitted flag set will never try to obtain a read-lock using this function. The only read-lock obtained
     // by a connection in read-uncommitted mode is on the sqlite_master table, and that lock is obtained in BtreeBeginTrans().
     Debug.Assert((DB.flags & sqlite3b.SQLITE.ReadUncommitted) == 0 || eLock == LOCK.WRITE);
     // This function should only be called on a sharable b-tree after it has been determined that no other b-tree holds a conflicting lock.
     Debug.Assert(Sharable);
     Debug.Assert(querySharedCacheTableLock(tableID, eLock) == RC.OK);
     // First search the list for an existing lock on this table.
     BtreeLock pLock = null;
     for (var @lock = Shared.Locks; @lock != null; @lock = @lock.Next)
         if (@lock.TableID == tableID && @lock.Tree == this)
         {
             pLock = @lock;
             break;
         }
     // If the above search did not find a BtLock struct associating Btree p with table iTable, allocate one and link it into the list.
     if (pLock == null)
     {
         var shared = Shared;
         pLock = new BtreeLock();
         pLock.TableID = tableID;
         pLock.Tree = this;
         pLock.Next = shared.Locks;
         shared.Locks = pLock;
     }
     // Set the BtLock.eLock variable to the maximum of the current lock and the requested lock. This means if a write-lock was already held
     // and a read-lock requested, we don't incorrectly downgrade the lock.
     Debug.Assert(LOCK.WRITE > LOCK.READ);
     if (eLock > pLock.Lock)
         pLock.Lock = eLock;
     return RC.OK;
 }
Esempio n. 8
0
 internal RC querySharedCacheTableLock(Pgno tableID, LOCK eLock)
 {
     Debug.Assert(sqlite3BtreeHoldsMutex());
     Debug.Assert(eLock == LOCK.READ || eLock == LOCK.WRITE);
     Debug.Assert(DB != null);
     Debug.Assert((DB.flags & sqlite3b.SQLITE.ReadUncommitted) == 0 || eLock == LOCK.WRITE || tableID == 1);
     // If requesting a write-lock, then the Btree must have an open write transaction on this file. And, obviously, for this to be so there
     // must be an open write transaction on the file itself.
     var shared = this.Shared;
     Debug.Assert(eLock == LOCK.READ || (shared.Writer == this && InTransaction == TRANS.WRITE));
     Debug.Assert(eLock == LOCK.READ || shared.InTransaction == TRANS.WRITE);
     // This routine is a no-op if the shared-cache is not enabled
     if (!Sharable)
         return RC.OK;
     // If some other connection is holding an exclusive lock, the requested lock may not be obtained.
     if (shared.Writer != this && shared.IsExclusive)
     {
         sqlite3b.sqlite3ConnectionBlocked(DB, shared.Writer.DB);
         return RC.LOCKED_SHAREDCACHE;
     }
     for (var @lock = shared.Locks; @lock != null; @lock = @lock.Next)
     {
         // The condition (pIter.eLock!=eLock) in the following if(...) statement is a simplification of:
         //   (eLock==WRITE_LOCK || pIter.eLock==WRITE_LOCK)
         // since we know that if eLock==WRITE_LOCK, then no other connection may hold a WRITE_LOCK on any table in this file (since there can
         // only be a single writer).
         Debug.Assert(@lock.Lock == LOCK.READ || @lock.Lock == LOCK.WRITE);
         Debug.Assert(eLock == LOCK.READ || @lock.Tree == this || @lock.Lock == LOCK.READ);
         if (@lock.Tree != this && @lock.TableID == tableID && @lock.Lock != eLock)
         {
             sqlite3b.sqlite3ConnectionBlocked(DB, @lock.Tree.DB);
             if (eLock == LOCK.WRITE)
             {
                 Debug.Assert(shared.Writer == this);
                 shared.IsPending = true;
             }
             return RC.LOCKED_SHAREDCACHE;
         }
     }
     return RC.OK;
 }