Пример #1
0
        public static RC Open(VSystem vfs, string filename, BContext ctx, ref Btree btree, OPEN flags, VSystem.OPEN vfsFlags)
        {
            // True if opening an ephemeral, temporary database
            bool tempDB = string.IsNullOrEmpty(filename);

            // Set the variable isMemdb to true for an in-memory database, or false for a file-based database.
            bool memoryDB = (filename == ":memory:") ||
                (tempDB && ctx.TempInMemory()) ||
                (vfsFlags & VSystem.OPEN.MEMORY) != 0;

            Debug.Assert(ctx != null);
            Debug.Assert(vfs != null);
            Debug.Assert(MutexEx.Held(ctx.Mutex));
            Debug.Assert(((uint)flags & 0xff) == (uint)flags); // flags fit in 8 bits

            // Only a BTREE_SINGLE database can be BTREE_UNORDERED
            Debug.Assert((flags & OPEN.UNORDERED) == 0 || (flags & OPEN.SINGLE) != 0);

            // A BTREE_SINGLE database is always a temporary and/or ephemeral
            Debug.Assert((flags & OPEN.SINGLE) == 0 || tempDB);

            if (memoryDB)
                flags |= OPEN.MEMORY;
            if ((vfsFlags & VSystem.OPEN.MAIN_DB) != 0 && (memoryDB || tempDB))
                vfsFlags = (vfsFlags & ~VSystem.OPEN.MAIN_DB) | VSystem.OPEN.TEMP_DB;
            var p = new Btree(); // Handle to return
            if (p == null)
                return RC.NOMEM;
            p.InTrans = TRANS.NONE;
            p.Ctx = ctx;
#if !OMIT_SHARED_CACHE
            p.Lock.Btree = p;
            p.Lock.Table = 1;
#endif

            RC rc = RC.OK; // Result code from this function
            BtShared bt = null; // Shared part of btree structure
            MutexEx mutexOpen = null;
#if !OMIT_SHARED_CACHE && !OMIT_DISKIO
            // If this Btree is a candidate for shared cache, try to find an existing BtShared object that we can share with
            if (!tempDB && (!memoryDB || (vfsFlags & VSystem.OPEN.URI) != 0))
                if ((vfsFlags & VSystem.OPEN.SHAREDCACHE) != 0)
                {
                    string fullPathname;
                    p.Sharable_ = true;
                    if (memoryDB)
                        fullPathname = filename;
                    else
                        vfs.FullPathname(filename, out fullPathname);
                    MutexEx mutexShared;
#if THREADSAFE
                    mutexOpen = MutexEx.Alloc(MutexEx.MUTEX.STATIC_OPEN); // Prevents a race condition. Ticket #3537
                    MutexEx.Enter(mutexOpen);
                    mutexShared = MutexEx.Alloc(MutexEx.MUTEX.STATIC_MASTER);
                    MutexEx.Enter(mutexShared);
#endif
                    for (bt = _sharedCacheList; bt != null; bt = bt.Next)
                    {
                        Debug.Assert(bt.Refs > 0);
                        if (fullPathname == bt.Pager.get_Filename(false) && bt.Pager.get_Vfs() == vfs)
                        {
                            for (var i = ctx.DBs.length - 1; i >= 0; i--)
                            {
                                var existing = ctx.DBs[i].Bt;
                                if (existing != null && existing.Bt == bt)
                                {
                                    MutexEx.Leave(mutexShared);
                                    MutexEx.Leave(mutexOpen);
                                    fullPathname = null;
                                    p = null;
                                    return RC.CONSTRAINT;
                                }
                            }
                            p.Bt = bt;
                            bt.Refs++;
                            break;
                        }
                    }
                    MutexEx.Leave(mutexShared);
                    fullPathname = null;
                }
#if DEBUG
                else
                    // In debug mode, we mark all persistent databases as sharable even when they are not.  This exercises the locking code and
                    // gives more opportunity for asserts(sqlite3_mutex_held()) statements to find locking problems.
                    p.Sharable_ = true;
#endif
#endif

            byte reserves; // Byte of unused space on each page
            var dbHeader = new byte[100]; // Database header content
            if (bt == null)
            {
                // The following asserts make sure that structures used by the btree are the right size.  This is to guard against size changes that result
                // when compiling on a different architecture.
                Debug.Assert(sizeof(long) == 8 || sizeof(long) == 4);
                Debug.Assert(sizeof(ulong) == 8 || sizeof(ulong) == 4);
                Debug.Assert(sizeof(uint) == 4);
                Debug.Assert(sizeof(ushort) == 2);
                Debug.Assert(sizeof(Pid) == 4);

                bt = new BtShared();
                if (bt == null)
                {
                    rc = RC.NOMEM;
                    goto btree_open_out;
                }
                rc = Pager.Open(vfs, out bt.Pager, filename, EXTRA_SIZE, (IPager.PAGEROPEN)flags, vfsFlags, pageReinit, null);
                if (rc == RC.OK)
                    rc = bt.Pager.ReadFileHeader(dbHeader.Length, dbHeader);
                if (rc != RC.OK)
                    goto btree_open_out;
                bt.OpenFlags = flags;
                bt.Ctx = ctx;
                bt.Pager.SetBusyHandler(btreeInvokeBusyHandler, bt);
                p.Bt = bt;

                bt.Cursor = null;
                bt.Page1 = null;
                if (bt.Pager.get_Readonly()) bt.BtsFlags |= BTS.READ_ONLY;
#if SECURE_DELETE
                bt.BtsFlags |= BTS.SECURE_DELETE;
#endif
                bt.PageSize = (Pid)((dbHeader[16] << 8) | (dbHeader[17] << 16));
                if (bt.PageSize < 512 || bt.PageSize > Pager.MAX_PAGE_SIZE || ((bt.PageSize - 1) & bt.PageSize) != 0)
                {
                    bt.PageSize = 0;
#if !OMIT_AUTOVACUUM
                    // If the magic name ":memory:" will create an in-memory database, then leave the autoVacuum mode at 0 (do not auto-vacuum), even if
                    // SQLITE_DEFAULT_AUTOVACUUM is true. On the other hand, if SQLITE_OMIT_MEMORYDB has been defined, then ":memory:" is just a
                    // regular file-name. In this case the auto-vacuum applies as per normal.
                    if (filename != null && !memoryDB)
                    {
                        bt.AutoVacuum = (DEFAULT_AUTOVACUUM != 0);
                        bt.IncrVacuum = (DEFAULT_AUTOVACUUM == AUTOVACUUM.INCR);
                    }
#endif
                    reserves = 0;
                }
                else
                {
                    reserves = dbHeader[20];
                    bt.BtsFlags |= BTS.PAGESIZE_FIXED;
#if !OMIT_AUTOVACUUM
                    bt.AutoVacuum = (ConvertEx.Get4(dbHeader, 36 + 4 * 4) != 0);
                    bt.IncrVacuum = (ConvertEx.Get4(dbHeader, 36 + 7 * 4) != 0);
#endif
                }
                rc = bt.Pager.SetPageSize(ref bt.PageSize, reserves);
                if (rc != RC.OK) goto btree_open_out;
                bt.UsableSize = (ushort)(bt.PageSize - reserves);
                Debug.Assert((bt.PageSize & 7) == 0); // 8-byte alignment of pageSize

#if !SHARED_CACHE && !OMIT_DISKIO
                // Add the new BtShared object to the linked list sharable BtShareds.
                if (p.Sharable_)
                {
                    bt.Refs = 1;
                    MutexEx mutexShared;
#if THREADSAFE
                    mutexShared = MutexEx.Alloc(MutexEx.MUTEX.STATIC_MASTER);
                    bt.Mutex = MutexEx.Alloc(MutexEx.MUTEX.FAST);
#endif
                    MutexEx.Enter(mutexShared);
                    bt.Next = _sharedCacheList;
                    _sharedCacheList = bt;
                    MutexEx.Leave(mutexShared);
                }
#endif
            }

#if !OMIT_SHARED_CACHE && !OMIT_DISKIO
            // If the new Btree uses a sharable pBtShared, then link the new Btree into the list of all sharable Btrees for the same connection.
            // The list is kept in ascending order by pBt address.
            if (p.Sharable_)
            {
                Btree sib;
                for (var i = 0; i < ctx.DBs.length; i++)
                    if ((sib = ctx.DBs[i].Bt) != null && sib.Sharable_)
                    {
                        while (sib.Prev != null) { sib = sib.Prev; }
                        if (p.Bt.AutoID < sib.Bt.AutoID)
                        {
                            p.Next = sib;
                            p.Prev = null;
                            sib.Prev = p;
                        }
                        else
                        {
                            while (sib.Next != null && sib.Next.Bt.AutoID < p.Bt.AutoID)
                                sib = sib.Next;
                            p.Next = sib.Next;
                            p.Prev = sib;
                            if (p.Next != null)
                                p.Next.Prev = p;
                            sib.Next = p;
                        }
                        break;
                    }
            }
#endif
            btree = p;

        btree_open_out:
            if (rc != RC.OK)
            {
                if (bt != null && bt.Pager != null)
                    bt.Pager.Close();
                bt = null;
                p = null;
                btree = null;
            }
            else
                // If the B-Tree was successfully opened, set the pager-cache size to the default value. Except, when opening on an existing shared pager-cache,
                // do not change the pager-cache size.
                if (p.Schema(0, null) == null)
                    p.Bt.Pager.SetCacheSize(DEFAULT_CACHE_SIZE);
#if THREADSAFE
            Debug.Assert(MutexEx.Held(mutexOpen));
            MutexEx.Leave(mutexOpen);
#endif
            return rc;
        }
Пример #2
0
 public static SCHEMA DbSetProperty(BContext D, int I, SCHEMA P)
 {
     return((D).DBs[I].Schema.Flags |= (P));
 }
Пример #3
0
 public static SCHEMA DbClearProperty(BContext D, int I, SCHEMA P)
 {
     return((D).DBs[I].Schema.Flags &= ~(P));
 }
Пример #4
0
 public void ConnectionBlocked(BContext blocked) { }
Пример #5
0
 public static bool DbHasAnyProperty(BContext D, int I, SCHEMA P)
 {
     return(((D).DBs[I].Schema.Flags & (P)) != 0);
 }
Пример #6
0
 public static TEXTENCODE CTXENCODE(BContext ctx) { return ctx.DBs[0].Schema.Encode; }
Пример #7
0
 public static void CTXENCODE(BContext ctx, TEXTENCODE encode) { ctx.DBs[0].Schema.Encode = encode; }
Пример #8
0
 public void ConnectionBlocked(BContext blocked)
 {
 }
Пример #9
0
 public static TEXTENCODE CTXENCODE(BContext ctx)
 {
     return(ctx.DBs[0].Schema.Encode);
 }
Пример #10
0
 public static void CTXENCODE(BContext ctx, TEXTENCODE encode)
 {
     ctx.DBs[0].Schema.Encode = encode;
 }
Пример #11
0
 static bool SchemaMutexHeld(BContext ctx, int db, Schema schema)
 {
     return(true);
 }
Пример #12
0
 static bool HoldsAllMutexes(BContext ctx)
 {
     return(true);
 }
Пример #13
0
 static void EnterAll(BContext ctx)
 {
 }
Пример #14
0
 public static void LeaveAll(BContext ctx)
 {
 }