public void TestRefresh()
        {
            testName = "TestRefresh";
            SetUpTest(true);
            string dbFileName    = testHome + "/" + testName + ".db";
            string dbSecFileName = testHome + "/" + testName +
                                   "_sec.db";

            BTreeDatabase          db;
            SecondaryBTreeDatabase secDB;

            OpenSecDB(dbFileName, dbSecFileName, out db,
                      out secDB);
            WriteRecords(db);

            SecondaryCursor cursor = secDB.SecondaryCursor();
            KeyValuePair <DatabaseEntry, KeyValuePair <
                              DatabaseEntry, DatabaseEntry> > pair;
            DatabaseEntry pKey, pData;

            pKey  = new DatabaseEntry(BitConverter.GetBytes((int)6));
            pData = new DatabaseEntry(BitConverter.GetBytes((int)10));
            pair  = new KeyValuePair <DatabaseEntry, KeyValuePair <
                                          DatabaseEntry, DatabaseEntry> >(pData,
                                                                          new KeyValuePair <DatabaseEntry, DatabaseEntry>(
                                                                              pKey, pData));
            cursor.Move(pair, true);
            Assert.IsTrue(cursor.Refresh());
            Assert.AreEqual(pData.Data, cursor.Current.Key.Data);
            Assert.AreEqual(pKey.Data, cursor.Current.Value.Key.Data);

            cursor.Close();
            secDB.Close();
            db.Close();
        }
Example #2
0
        public void TestMoveLast()
        {
            testName = "TestMoveLast";
            testHome = testFixtureHome + "/" + testName;
            string dbFileName    = testHome + "/" + testName + ".db";
            string dbSecFileName = testHome + "/" + testName +
                                   "_sec.db";

            Configuration.ClearDir(testHome);

            BTreeDatabase          db;
            SecondaryBTreeDatabase secDB;

            OpenSecDB(dbFileName, dbSecFileName, out db,
                      out secDB);
            WriteRecords(db);

            SecondaryCursor cursor = secDB.SecondaryCursor();

            Assert.IsTrue(cursor.MoveLast());
            Assert.AreEqual(BitConverter.GetBytes((int)10),
                            cursor.Current.Key.Data);

            cursor.Close();
            secDB.Close();
            db.Close();
        }
        public void TestCurrent()
        {
            testName = "TestCurrent";
            SetUpTest(true);
            string dbFileName    = testHome + "/" + testName + ".db";
            string dbSecFileName = testHome + "/" + testName +
                                   "_sec.db";

            // Open a primary database and its secondary database.
            BTreeDatabase          db;
            SecondaryBTreeDatabase secDB;

            OpenSecDB(dbFileName, dbSecFileName, out db, out secDB);

            // Put a pair of key and data into database.
            DatabaseEntry key, data;

            key = new DatabaseEntry(
                ASCIIEncoding.ASCII.GetBytes("key"));
            data = new DatabaseEntry(
                ASCIIEncoding.ASCII.GetBytes("data"));
            db.Put(key, data);

            // Delete the pair with cursor.
            SecondaryCursor secCursor = secDB.SecondaryCursor();

            Assert.IsTrue(secCursor.Move(data, true));

            // Confirm that the current is the one we put into database.
            Assert.AreEqual(data.Data, secCursor.Current.Key.Data);

            // Close all databases.
            secDB.Close();
            db.Close();
        }
Example #4
0
        public void GetSecCursor(BTreeDatabase db,
		    string secFileName, SecondaryKeyGenDelegate keyGen,
		    out SecondaryBTreeDatabase secDB,
		    out SecondaryCursor cursor, bool ifCfg,
		    DatabaseEntry data)
        {
            // Open secondary database.
            SecondaryBTreeDatabaseConfig secCfg =
                new SecondaryBTreeDatabaseConfig(db, keyGen);
            secCfg.Creation = CreatePolicy.IF_NEEDED;
            secCfg.Duplicates = DuplicatesPolicy.SORTED;
            secDB = SecondaryBTreeDatabase.Open(secFileName, secCfg);

            int[] intArray = new int[4];
            intArray[0] = 0;
            intArray[1] = 1;
            intArray[2] = 2049;
            intArray[3] = 65537;
            for (int i = 0; i < 4; i++)
            {
                DatabaseEntry record = new DatabaseEntry(
                    BitConverter.GetBytes(intArray[i]));
                db.Put(record, record);
            }

            // Get secondary cursor on the secondary database.
            if (ifCfg == false)
                cursor = secDB.SecondaryCursor();
            else
                cursor = secDB.SecondaryCursor(new CursorConfig());

            // Position the cursor.
            if (data != null)
                Assert.IsTrue(cursor.Move(data, true));
        }
Example #5
0
        public void TestMoveNextUnique()
        {
            testName = "TestMoveNextUnique";
            testHome = testFixtureHome + "/" + testName;
            string dbFileName    = testHome + "/" + testName + ".db";
            string dbSecFileName = testHome + "/" + testName +
                                   "_sec.db";

            Configuration.ClearDir(testHome);

            BTreeDatabase          db;
            SecondaryBTreeDatabase secDB;

            OpenSecDB(dbFileName, dbSecFileName, out db,
                      out secDB);
            WriteRecords(db);

            /*
             * Move cursor to duplicate record. Since the duplicate
             * record has the largest key, moving to the next
             * unique record should fail.
             */
            SecondaryCursor cursor = secDB.SecondaryCursor();

            cursor.Move(new DatabaseEntry(
                            BitConverter.GetBytes((int)10)), true);
            Assert.IsFalse(cursor.MoveNextUnique());

            cursor.Close();
            secDB.Close();
            db.Close();
        }
Example #6
0
        public void TestMovePrev()
        {
            testName = "TestMovePrev";
            testHome = testFixtureHome + "/" + testName;
            string dbFileName    = testHome + "/" + testName + ".db";
            string dbSecFileName = testHome + "/" + testName +
                                   "_sec.db";

            Configuration.ClearDir(testHome);

            BTreeDatabase          db;
            SecondaryBTreeDatabase secDB;

            OpenSecDB(dbFileName, dbSecFileName, out db,
                      out secDB);
            WriteRecords(db);

            SecondaryCursor cursor = secDB.SecondaryCursor();

            cursor.MoveLast();
            for (int i = 0; i < 5; i++)
            {
                Assert.IsTrue(cursor.MovePrev());
            }

            cursor.Close();
            secDB.Close();
            db.Close();
        }
        public void TestMoveNext()
        {
            testName = "TestMoveNext";
            SetUpTest(true);
            string dbFileName    = testHome + "/" + testName + ".db";
            string dbSecFileName = testHome + "/" + testName +
                                   "_sec.db";

            BTreeDatabase          db;
            SecondaryBTreeDatabase secDB;

            OpenSecDB(dbFileName, dbSecFileName, out db,
                      out secDB);
            WriteRecords(db);

            SecondaryCursor cursor = secDB.SecondaryCursor();

            cursor.MoveFirst();
            for (int i = 0; i < 5; i++)
            {
                Assert.IsTrue(cursor.MoveNext());
            }

            cursor.Close();
            secDB.Close();
            db.Close();
        }
Example #8
0
        public void TestMoveNextDuplicate()
        {
            testName = "TestMoveNextDuplicate";
            testHome = testFixtureHome + "/" + testName;
            string dbFileName    = testHome + "/" + testName + ".db";
            string dbSecFileName = testHome + "/" + testName +
                                   "_sec.db";

            Configuration.ClearDir(testHome);

            BTreeDatabase          db;
            SecondaryBTreeDatabase secDB;

            OpenSecDB(dbFileName, dbSecFileName, out db,
                      out secDB);
            WriteRecords(db);

            // Create a cursor and move the cursor to duplicate record.
            SecondaryCursor cursor = secDB.SecondaryCursor();

            cursor.Move(new DatabaseEntry(
                            BitConverter.GetBytes((int)10)), true);
            Assert.IsTrue(cursor.MoveNextDuplicate());
            Assert.AreEqual(BitConverter.GetBytes((int)10),
                            cursor.Current.Key.Data);

            cursor.Close();
            secDB.Close();
            db.Close();
        }
Example #9
0
        protected Repository(string databaseName, ILoggerFactory loggerFactory)
        {
            path   = Environment.GetEnvironmentVariable("DATA_DIR");
            logger = loggerFactory.CreateLogger(databaseName);
            var cfg = new BTreeDatabaseConfig
            {
                Creation      = CreatePolicy.IF_NEEDED,
                CacheSize     = new CacheInfo(1, 0, 1),
                ErrorFeedback = (prefix, message) =>
                {
                    logger.LogError($"{DateTime.Now} [primary] {prefix}: {message}");
                },
                ErrorPrefix = databaseName
            };

            db = BTreeDatabase.Open(Path.Combine(path, databaseName + ".db"), cfg);

            //set up secondary database
            var scfg = new SecondaryBTreeDatabaseConfig(db, GenerateIndex)
            {
                Creation      = CreatePolicy.IF_NEEDED,
                Duplicates    = DuplicatesPolicy.SORTED,
                ErrorFeedback = (prefix, message) =>
                {
                    logger.LogError($"{DateTime.Now} [secondary] {prefix}: {message}");
                }
            };

            indexDb = SecondaryBTreeDatabase.Open(Path.Combine(path, databaseName + "-index.db"), scfg);

            cursor  = db.Cursor();
            scursor = indexDb.SecondaryCursor();
        }
Example #10
0
        public void TestMoveFirst()
        {
            testName = "TestMoveFirst";
            testHome = testFixtureHome + "/" + testName;
            string dbFileName    = testHome + "/" + testName + ".db";
            string dbSecFileName = testHome + "/" + testName +
                                   "_sec.db";

            Configuration.ClearDir(testHome);

            // Open primary and secondary database.
            BTreeDatabase          db;
            SecondaryBTreeDatabase secDB;

            OpenSecDB(dbFileName, dbSecFileName, out db,
                      out secDB);


            // Write ten records into the database.
            WriteRecords(db);

            // Move the cursor to the first record(0,0).
            SecondaryCursor cursor = secDB.SecondaryCursor();

            Assert.IsTrue(cursor.MoveFirst());
            Assert.AreEqual(BitConverter.GetBytes((int)0),
                            cursor.Current.Key.Data);

            // Close all.
            cursor.Close();
            secDB.Close();
            db.Close();
        }
Example #11
0
        public void TestMovePrevDuplicateWithLockingInfo()
        {
            testName = "TestMovePrevDuplicateWithLockingInfo";
            testHome = testFixtureHome + "/" + testName;
            string dbFileName    = testName + ".db";
            string dbSecFileName = testName + "_sec.db";

            Configuration.ClearDir(testHome);

            /*
             * Open environment, primary database and
             * secondary database.
             */
            BTreeDatabase          db;
            DatabaseEnvironment    env;
            SecondaryBTreeDatabase secDB;

            OpenSecDBInTxn(testHome, dbFileName,
                           dbSecFileName, out env, out db, out secDB);

            // Write ten records into the database.
            WriteRecordsInTxn(db, env);

            Transaction     cursorTxn = env.BeginTransaction();
            SecondaryCursor cursor    =
                secDB.SecondaryCursor(cursorTxn);
            LockingInfo lockingInfo = new LockingInfo();

            lockingInfo.IsolationDegree = Isolation.DEGREE_TWO;
            lockingInfo.ReadModifyWrite = true;

            /*
             * Move the cursor to the record(10,6), that is the
             * record(6, 10) in the primary database. Move to
             * its previous duplicate record, that is (10,5).
             */
            KeyValuePair <DatabaseEntry, KeyValuePair <
                              DatabaseEntry, DatabaseEntry> > pair;
            DatabaseEntry pKey, pData;

            pKey  = new DatabaseEntry(BitConverter.GetBytes((int)6));
            pData = new DatabaseEntry(BitConverter.GetBytes((int)10));
            pair  = new KeyValuePair <DatabaseEntry, KeyValuePair <
                                          DatabaseEntry, DatabaseEntry> >(pData,
                                                                          new KeyValuePair <DatabaseEntry, DatabaseEntry>(
                                                                              pKey, pData));
            cursor.Move(pair, true, lockingInfo);
            Assert.IsTrue(cursor.MovePrevDuplicate(lockingInfo));
            Assert.AreEqual(BitConverter.GetBytes((int)10),
                            cursor.Current.Key.Data);

            cursor.Close();
            cursorTxn.Commit();

            // Close all.
            secDB.Close();
            db.Close();
            env.Close();
        }
        public void TestMovePrevUniqueWithLockingInfo()
        {
            testName = "TestMovePrevUniqueWithLockingInfo";
            SetUpTest(true);
            string dbFileName    = testName + ".db";
            string dbSecFileName = testName + "_sec.db";

            /*
             * Open environment, primary database and
             * secondary database.
             */
            BTreeDatabase          db;
            DatabaseEnvironment    env;
            SecondaryBTreeDatabase secDB;

            OpenSecDBInTxn(testHome, dbFileName,
                           dbSecFileName, out env, out db, out secDB);

            // Write ten records into the database.
            WriteRecordsInTxn(db, env);

            Transaction     cursorTxn = env.BeginTransaction();
            SecondaryCursor cursor    =
                secDB.SecondaryCursor(cursorTxn);
            LockingInfo lockingInfo = new LockingInfo();

            lockingInfo.IsolationDegree = Isolation.DEGREE_TWO;
            lockingInfo.ReadModifyWrite = true;

            /*
             * Move the cursor to the record(10, 6) and move to the
             * previous unique record which has different key from
             * the record(10,6).
             */
            KeyValuePair <DatabaseEntry, KeyValuePair <
                              DatabaseEntry, DatabaseEntry> > pair;
            DatabaseEntry pKey, pData;

            pKey  = new DatabaseEntry(BitConverter.GetBytes((int)6));
            pData = new DatabaseEntry(BitConverter.GetBytes((int)10));
            pair  = new KeyValuePair <DatabaseEntry, KeyValuePair <
                                          DatabaseEntry, DatabaseEntry> >(pData,
                                                                          new KeyValuePair <DatabaseEntry, DatabaseEntry>(
                                                                              pKey, pData));
            cursor.Move(pair, true, lockingInfo);
            Assert.IsTrue(cursor.MovePrevUnique(lockingInfo));
            Assert.AreNotEqual(BitConverter.GetBytes((int)10),
                               cursor.Current.Key.Data);

            cursor.Close();
            cursorTxn.Commit();

            // Close all.
            secDB.Close();
            db.Close();
            env.Close();
        }
Example #13
0
        public void TestMoveNextDuplicateWithLockingInfo()
        {
            testName = "TestMoveNextDuplicateWithLockingInfo";
            testHome = testFixtureHome + "/" + testName;
            string dbFileName    = testName + ".db";
            string dbSecFileName = testName + "_sec.db";

            Configuration.ClearDir(testHome);

            /*
             * Open environment, primary database and
             * secondary database.
             */
            BTreeDatabase          db;
            DatabaseEnvironment    env;
            SecondaryBTreeDatabase secDB;

            OpenSecDBInTxn(testHome, dbFileName,
                           dbSecFileName, out env, out db, out secDB);

            // Write ten records into the database.
            WriteRecordsInTxn(db, env);

            /*
             * Create a cursor and move the cursor to duplicate
             * record(10, 5), that is record(5,10) in primary database.
             * Then move the cursor to the next duplicate record
             * (10, 6), that is record(6,10) in primary database.
             */
            Transaction     cursorTxn = env.BeginTransaction();
            SecondaryCursor cursor    =
                secDB.SecondaryCursor(cursorTxn);
            LockingInfo lockingInfo = new LockingInfo();

            lockingInfo.IsolationDegree = Isolation.DEGREE_THREE;
            lockingInfo.ReadModifyWrite = true;
            cursor.Move(new DatabaseEntry(
                            BitConverter.GetBytes((int)10)), true, lockingInfo);
            Assert.IsTrue(cursor.MoveNextDuplicate(lockingInfo));
            Assert.AreEqual(BitConverter.GetBytes((int)10),
                            cursor.Current.Key.Data);
            cursor.Close();
            cursorTxn.Commit();

            // Close all.
            secDB.Close();
            db.Close();
            env.Close();
        }
Example #14
0
        public void MoveToPos(string dbFileName,
                              string dbSecFileName, bool ifPair)
        {
            // Open a primary database and its secondary database.
            BTreeDatabase          db;
            SecondaryBTreeDatabase secDB;

            OpenSecDB(dbFileName, dbSecFileName, out db,
                      out secDB);

            // Write ten records into the database.
            WriteRecords(db);

            SecondaryCursor secCursor = secDB.SecondaryCursor();
            DatabaseEntry   key       = new DatabaseEntry(
                BitConverter.GetBytes((int)0));
            DatabaseEntry notExistingKey = new DatabaseEntry(
                BitConverter.GetBytes((int)100));

            if (ifPair == false)
            {
                Assert.IsTrue(secCursor.Move(key, true));
                Assert.IsFalse(secCursor.Move(notExistingKey, true));
            }
            else
            {
                KeyValuePair <DatabaseEntry, KeyValuePair <
                                  DatabaseEntry, DatabaseEntry> > pair =
                    new KeyValuePair <DatabaseEntry,
                                      KeyValuePair <DatabaseEntry, DatabaseEntry> >(key,
                                                                                    new KeyValuePair <DatabaseEntry, DatabaseEntry>(
                                                                                        key, key));

                KeyValuePair <DatabaseEntry, KeyValuePair <
                                  DatabaseEntry, DatabaseEntry> > notExistingPair;

                notExistingPair = new KeyValuePair <DatabaseEntry,
                                                    KeyValuePair <DatabaseEntry, DatabaseEntry> >(
                    notExistingKey, new KeyValuePair <
                        DatabaseEntry, DatabaseEntry>(
                        notExistingKey, notExistingKey));
                Assert.IsTrue(secCursor.Move(pair, true));
                Assert.IsFalse(secCursor.Move(notExistingPair, true));
            }

            secCursor.Close();
            secDB.Close();
            db.Close();
        }
Example #15
0
        public void TestMovePrevWithLockingInfo()
        {
            testName = "TestMovePrevWithLockingInfo";
            testHome = testFixtureHome + "/" + testName;
            string dbFileName    = testName + ".db";
            string dbSecFileName = testName + "_sec.db";

            Configuration.ClearDir(testHome);

            /*
             * Open environment, primary database and
             * secondary database.
             */
            BTreeDatabase          db;
            DatabaseEnvironment    env;
            SecondaryBTreeDatabase secDB;

            OpenSecDBInTxn(testHome, dbFileName,
                           dbSecFileName, out env, out db, out secDB);

            // Write ten records into the database.
            WriteRecordsInTxn(db, env);

            /*
             * Move the cursor to the last record and move to its
             * previous record for five times.
             */
            Transaction     cursorTxn = env.BeginTransaction();
            SecondaryCursor cursor    =
                secDB.SecondaryCursor(cursorTxn);
            LockingInfo lockingInfo = new LockingInfo();

            lockingInfo.IsolationDegree = Isolation.DEGREE_TWO;
            lockingInfo.ReadModifyWrite = true;
            cursor.MoveLast(lockingInfo);
            for (int i = 0; i < 5; i++)
            {
                Assert.IsTrue(cursor.MovePrev(lockingInfo));
            }
            cursor.Close();
            cursorTxn.Commit();

            // Close all.
            secDB.Close();
            db.Close();
            env.Close();
        }
Example #16
0
        public void TestJoin()
        {
            testName = "TestJoin";
            SetUpTest(true);
            string dbFileName   = testHome + "/" + testName + ".db";
            string secFileName1 = testHome + "/" + "sec_" + testName + "1.db";
            string secFileName2 = testHome + "/" + "sec_" + testName + "2.db";

            // Open a primary database.
            BTreeDatabaseConfig dbCfg = new BTreeDatabaseConfig();

            dbCfg.Creation = CreatePolicy.IF_NEEDED;
            BTreeDatabase db = BTreeDatabase.Open(dbFileName, dbCfg);

            for (int i = 0; i < 10; i++)
            {
                db.Put(new DatabaseEntry(BitConverter.GetBytes(i)),
                       new DatabaseEntry(BitConverter.GetBytes(i)));
            }

            /*
             * Open two databases, their secondary databases and
             * secondary cursors.
             */
            SecondaryBTreeDatabase secDB1, secDB2;

            SecondaryCursor[] cursors = new SecondaryCursor[2];
            GetSecCursor(db, secFileName1,
                         new SecondaryKeyGenDelegate(KeyGenOnBigByte),
                         out secDB1, out cursors[0], false, null);
            GetSecCursor(db, secFileName2,
                         new SecondaryKeyGenDelegate(KeyGenOnLittleByte),
                         out secDB2, out cursors[1], true, null);

            // Get join cursor.
            JoinCursor joinCursor = db.Join(cursors, true);

            Assert.IsNotNull(joinCursor.GetEnumerator().Current);

            // Close all.
            joinCursor.Dispose();
            cursors[0].Close();
            cursors[1].Close();
            secDB1.Close();
            secDB2.Close();
            db.Close();
        }
Example #17
0
        public void TestMoveNextUniqueWithLockingInfo()
        {
            testName = "TestMoveNextUniqueWithLockingInfo";
            testHome = testFixtureHome + "/" + testName;
            string dbFileName    = testName + ".db";
            string dbSecFileName = testName + "_sec.db";

            Configuration.ClearDir(testHome);

            /*
             * Open environment, primary database and
             * secondary database.
             */
            BTreeDatabase          db;
            DatabaseEnvironment    env;
            SecondaryBTreeDatabase secDB;

            OpenSecDBInTxn(testHome, dbFileName,
                           dbSecFileName, out env, out db, out secDB);

            // Write ten records into the database.
            WriteRecordsInTxn(db, env);

            /*
             * Move cursor to duplicate record. Since the duplicate
             * record has the largest key, moving to the next
             * unique record should fail.
             */
            Transaction     cursorTxn = env.BeginTransaction();
            SecondaryCursor cursor    =
                secDB.SecondaryCursor(cursorTxn);
            LockingInfo lockingInfo = new LockingInfo();

            lockingInfo.IsolationDegree = Isolation.DEGREE_THREE;
            lockingInfo.ReadModifyWrite = true;
            cursor.Move(new DatabaseEntry(
                            BitConverter.GetBytes((int)10)), true);
            Assert.IsFalse(cursor.MoveNextUnique());
            cursor.Close();
            cursorTxn.Commit();

            // Close all.
            secDB.Close();
            db.Close();
            env.Close();
        }
Example #18
0
        public void MoveToPosWithLockingInfo(string home,
                                             string dbFileName, string dbSecFileName, bool ifPair)
        {
            // Open a primary database and its secondary database.
            BTreeDatabase          db;
            DatabaseEnvironment    env;
            SecondaryBTreeDatabase secDB;

            OpenSecDBInTxn(home, dbFileName, dbSecFileName,
                           out env, out db, out secDB);

            // Write ten records into the database.
            WriteRecordsInTxn(db, env);

            // Create an secondary cursor.
            Transaction     cursorTxn = env.BeginTransaction();
            SecondaryCursor secCursor = secDB.SecondaryCursor(
                cursorTxn);
            DatabaseEntry key = new DatabaseEntry(
                BitConverter.GetBytes((int)0));
            LockingInfo lockingInfo = new LockingInfo();

            lockingInfo.IsolationDegree = Isolation.DEGREE_THREE;
            lockingInfo.ReadModifyWrite = true;
            if (ifPair == false)
            {
                Assert.IsTrue(secCursor.Move(key, true, lockingInfo));
            }
            else
            {
                KeyValuePair <DatabaseEntry, KeyValuePair <
                                  DatabaseEntry, DatabaseEntry> > pair;

                pair = new KeyValuePair <DatabaseEntry,
                                         KeyValuePair <DatabaseEntry, DatabaseEntry> >(key,
                                                                                       new KeyValuePair <DatabaseEntry, DatabaseEntry>(
                                                                                           key, key));
                Assert.IsTrue(secCursor.Move(pair, true, lockingInfo));
            }
            secCursor.Close();
            cursorTxn.Commit();

            secDB.Close();
            db.Close();
            env.Close();
        }
Example #19
0
        /// <exception cref="InvalidOperationException">Missed secondary key for some criterion.</exception>
        public virtual IEnumerable <DatabaseEntry> GetByJoin(IBDbEntityInfo info, ICollection <IDataCriterion> criteria)
        {
            var        cursorsLength    = 0;
            var        secondaryCursors = new SecondaryCursor[criteria.Count];
            JoinCursor joinCursor       = null;

            try {
                var primaryDb = _schema.GetPrimaryDb(info.EntityName);

                foreach (var criterion in criteria)
                {
                    SecondaryKeyAttribute secondaryKey;
                    if (!info.SecondaryKeys.TryGetValue(criterion.Name, out secondaryKey))
                    {
                        var msg = $"Missed secondaty key '{criterion.Name}' for entity {info.EntityName} ({info.EntityType}).";
                        Log.TraceEvent(TraceEventType.Critical, msg);
                        throw new InvalidOperationException(msg);
                    }

                    var secondaryDb = _schema.GetSecondaryDb(primaryDb, secondaryKey);

                    var cursor = secondaryDb.SecondaryCursor();
                    secondaryCursors[cursorsLength++] = cursor;

                    var key = new DatabaseEntry(criterion.Value.ToBinnary());
                    if (!cursor.Move(key, exact:true))
                    {
                        yield break;
                    }
                }

                joinCursor = primaryDb.Join(secondaryCursors, true);
                while (joinCursor.MoveNext())
                {
                    yield return(joinCursor.Current.Value);
                }
            }
            finally {
                joinCursor?.Close();

                for (var i = 0; i < cursorsLength; i++)
                {
                    secondaryCursors[i].Close();
                }
            }
        }
        public void TestMoveNextWithLockingInfo()
        {
            testName = "TestMoveNextWithLockingInfo";
            SetUpTest(true);
            string dbFileName    = testName + ".db";
            string dbSecFileName = testName + "_sec.db";

            /*
             * Open environment, primary database and
             * secondary database.
             */
            BTreeDatabase          db;
            DatabaseEnvironment    env;
            SecondaryBTreeDatabase secDB;

            OpenSecDBInTxn(testHome, dbFileName, dbSecFileName,
                           out env, out db, out secDB);

            // Write ten records into the database.
            WriteRecordsInTxn(db, env);

            /*
             * Move cursor to the first record and move to next
             * record for five times.
             */
            Transaction     cursorTxn = env.BeginTransaction();
            SecondaryCursor cursor    =
                secDB.SecondaryCursor(cursorTxn);
            LockingInfo lockingInfo = new LockingInfo();

            lockingInfo.IsolationDegree = Isolation.DEGREE_THREE;
            lockingInfo.ReadModifyWrite = true;
            cursor.MoveFirst(lockingInfo);
            for (int i = 0; i < 5; i++)
            {
                Assert.IsTrue(cursor.MoveNext(lockingInfo));
            }
            cursor.Close();
            cursorTxn.Commit();

            // Close all.
            secDB.Close();
            db.Close();
            env.Close();
        }
Example #21
0
        public void TestSecondaryCursor()
        {
            testName = "TestSecondaryCursor";
            testHome = testFixtureHome + "/" + testName;
            string dbFileName = testHome + "/" + testName + ".db";

            Configuration.ClearDir(testHome);

            // Open primary database.
            BTreeDatabaseConfig primaryDBConfig =
                new BTreeDatabaseConfig();

            primaryDBConfig.Creation = CreatePolicy.IF_NEEDED;
            BTreeDatabase primaryDB =
                BTreeDatabase.Open(dbFileName, primaryDBConfig);

            // Open secondary database.
            SecondaryBTreeDatabaseConfig secDBConfig =
                new SecondaryBTreeDatabaseConfig(primaryDB,
                                                 new SecondaryKeyGenDelegate(SecondaryKeyGen));
            SecondaryBTreeDatabase secDB =
                SecondaryBTreeDatabase.Open(dbFileName,
                                            secDBConfig);

            primaryDB.Put(new DatabaseEntry(
                              BitConverter.GetBytes((int)1)),
                          new DatabaseEntry(BitConverter.GetBytes((int)11)));


            SecondaryCursor cursor = secDB.SecondaryCursor();

            cursor.Move(new DatabaseEntry(
                            BitConverter.GetBytes((int)11)), true);
            Assert.AreEqual(BitConverter.GetBytes((int)11),
                            cursor.Current.Key.Data);

            // Close the cursor.
            cursor.Close();

            // Close secondary database.
            secDB.Close();

            // Close primary database.
            primaryDB.Close();
        }
        public void TestMoveLastWithLockingInfo()
        {
            testName = "TestMoveLastWithLockingInfo";
            SetUpTest(true);
            string dbFileName    = testName + ".db";
            string dbSecFileName = testName + "_sec.db";

            /*
             * Open environment, primary database and
             * secondary database.
             */
            BTreeDatabase          db;
            DatabaseEnvironment    env;
            SecondaryBTreeDatabase secDB;

            OpenSecDBInTxn(testHome, dbFileName, dbSecFileName,
                           out env, out db, out secDB);

            // Write ten records into the database.
            WriteRecordsInTxn(db, env);

            /*
             * Move the cursor to the last record(10, 6), that is
             * record(6, 10) in primary database.
             */
            Transaction     cursorTxn = env.BeginTransaction();
            SecondaryCursor cursor    =
                secDB.SecondaryCursor(cursorTxn);
            LockingInfo lockingInfo = new LockingInfo();

            lockingInfo.IsolationDegree = Isolation.DEGREE_THREE;
            lockingInfo.ReadModifyWrite = true;
            Assert.IsTrue(cursor.MoveLast(lockingInfo));
            Assert.AreEqual(BitConverter.GetBytes((int)10),
                            cursor.Current.Key.Data);
            cursor.Close();
            cursorTxn.Commit();

            // Close all.
            secDB.Close();
            db.Close();
            env.Close();
        }
Example #23
0
        public void GetSecCursor(BTreeDatabase db,
                                 string secFileName, SecondaryKeyGenDelegate keyGen,
                                 out SecondaryBTreeDatabase secDB,
                                 out SecondaryCursor cursor, bool ifCfg,
                                 DatabaseEntry data)
        {
            // Open secondary database.
            SecondaryBTreeDatabaseConfig secCfg =
                new SecondaryBTreeDatabaseConfig(db, keyGen);

            secCfg.Creation   = CreatePolicy.IF_NEEDED;
            secCfg.Duplicates = DuplicatesPolicy.SORTED;
            secDB             = SecondaryBTreeDatabase.Open(secFileName, secCfg);

            int[] intArray = new int[4];
            intArray[0] = 0;
            intArray[1] = 1;
            intArray[2] = 2049;
            intArray[3] = 65537;
            for (int i = 0; i < 4; i++)
            {
                DatabaseEntry record = new DatabaseEntry(
                    BitConverter.GetBytes(intArray[i]));
                db.Put(record, record);
            }

            // Get secondary cursor on the secondary database.
            if (ifCfg == false)
            {
                cursor = secDB.SecondaryCursor();
            }
            else
            {
                cursor = secDB.SecondaryCursor(new CursorConfig());
            }

            // Position the cursor.
            if (data != null)
            {
                Assert.IsTrue(cursor.Move(data, true));
            }
        }
Example #24
0
        public void TestGetEnumerator()
        {
            testName = "TestGetEnumerator";
            testHome = testFixtureHome + "/" + testName;
            string dbFileName    = testHome + "/" + testName + ".db";
            string dbSecFileName = testHome + "/" + testName +
                                   "_sec.db";

            Configuration.ClearDir(testHome);

            // Open a primary database and its secondary database.
            BTreeDatabase          db;
            SecondaryBTreeDatabase secDB;

            OpenSecDB(dbFileName, dbSecFileName, out db,
                      out secDB);

            // Write ten records into the database.
            WriteRecords(db);

            /*
             * Get all records from the secondary database and see
             * if the records with key other than 10 have the same as
             * their primary key.
             */
            SecondaryCursor secCursor = secDB.SecondaryCursor();

            foreach (KeyValuePair <DatabaseEntry, KeyValuePair <
                                       DatabaseEntry, DatabaseEntry> > secData in secCursor)
            {
                if (BitConverter.ToInt32(secData.Key.Data, 0) != 10)
                {
                    Assert.AreEqual(secData.Value.Key.Data,
                                    secData.Value.Value.Data);
                }
            }

            // Close all cursors and databases.
            secCursor.Close();
            secDB.Close();
            db.Close();
        }
Example #25
0
        public void TestJoin()
        {
            testName = "TestJoin";
            testHome = testFixtureHome + "/" + testName;
            string dbFileName   = testHome + "/" + testName + ".db";
            string secFileName1 = testHome + "/" + "sec_" + testName + "1.db";
            string secFileName2 = testHome + "/" + "sec_" + testName + "2.db";

            Configuration.ClearDir(testHome);

            // Open a primary database.
            BTreeDatabaseConfig dbCfg = new BTreeDatabaseConfig();

            dbCfg.Creation = CreatePolicy.IF_NEEDED;
            BTreeDatabase db = BTreeDatabase.Open(dbFileName, dbCfg);

            /*
             * Open two databases, their secondary databases and
             * secondary cursors.
             */
            SecondaryBTreeDatabase secDB1, secDB2;

            SecondaryCursor[] cursors = new SecondaryCursor[2];
            GetSecCursor(db, secFileName1,
                         new SecondaryKeyGenDelegate(KeyGenOnBigByte),
                         out secDB1, out cursors[0], false, null);
            GetSecCursor(db, secFileName2,
                         new SecondaryKeyGenDelegate(KeyGenOnLittleByte),
                         out secDB2, out cursors[1], true, null);

            // Get join cursor.
            JoinCursor joinCursor = db.Join(cursors, true);

            // Close all.
            joinCursor.Close();
            cursors[0].Close();
            cursors[1].Close();
            secDB1.Close();
            secDB2.Close();
            db.Close();
        }
Example #26
0
        public void TestSecondaryCursorWithConfig()
        {
            testName = "TestSecondaryCursorWithConfig";
            testHome = testFixtureHome + "/" + testName;
            string dbFileName = testHome + "/" + testName + ".db";

            Configuration.ClearDir(testHome);

            BTreeDatabase          db;
            SecondaryBTreeDatabase secDB;

            OpenPrimaryAndSecondaryDB(dbFileName, out db, out secDB);

            for (int i = 0; i < 10; i++)
            {
                db.Put(new DatabaseEntry(BitConverter.GetBytes(i)),
                       new DatabaseEntry(BitConverter.GetBytes((int)i)));
            }

            CursorConfig cursorConfig = new CursorConfig();

            cursorConfig.WriteCursor = false;
            SecondaryCursor cursor =
                secDB.SecondaryCursor(cursorConfig);

            cursor.Move(new DatabaseEntry(
                            BitConverter.GetBytes((int)5)), true);

            Assert.AreEqual(1, cursor.Count());

            // Close the cursor.
            cursor.Close();

            // Close secondary database.
            secDB.Close();

            // Close primary database.
            db.Close();
        }
Example #27
0
        public void TestDelete()
        {
            testName = "TestDelete";
            testHome = testFixtureHome + "/" + testName;
            string dbFileName    = testHome + "/" + testName + ".db";
            string dbSecFileName = testHome + "/" + testName +
                                   "_sec.db";

            Configuration.ClearDir(testHome);

            // Open a primary database and its secondary database.
            BTreeDatabase          db;
            SecondaryBTreeDatabase secDB;

            OpenSecDB(dbFileName, dbSecFileName, out db, out secDB);

            // Put a pair of key and data into database.
            DatabaseEntry key, data;

            key = new DatabaseEntry(
                ASCIIEncoding.ASCII.GetBytes("key"));
            data = new DatabaseEntry(
                ASCIIEncoding.ASCII.GetBytes("data"));
            db.Put(key, data);

            // Delete the pair with cursor.
            SecondaryCursor secCursor = secDB.SecondaryCursor();

            Assert.IsTrue(secCursor.MoveFirst());
            secCursor.Delete();

            // Confirm that the pair is deleted.
            Assert.IsFalse(db.Exists(key));

            // Close all databases.
            secDB.Close();
            db.Close();
        }
Example #28
0
        public void TestMovePrevUnique()
        {
            testName = "TestMovePrevUnique";
            testHome = testFixtureHome + "/" + testName;
            string dbFileName    = testHome + "/" + testName + ".db";
            string dbSecFileName = testHome + "/" + testName +
                                   "_sec.db";

            Configuration.ClearDir(testHome);

            BTreeDatabase          db;
            SecondaryBTreeDatabase secDB;

            OpenSecDB(dbFileName, dbSecFileName, out db,
                      out secDB);
            WriteRecords(db);

            SecondaryCursor cursor = secDB.SecondaryCursor();
            KeyValuePair <DatabaseEntry, KeyValuePair <
                              DatabaseEntry, DatabaseEntry> > pair;
            DatabaseEntry pKey, pData;

            pKey  = new DatabaseEntry(BitConverter.GetBytes((int)6));
            pData = new DatabaseEntry(BitConverter.GetBytes((int)10));
            pair  = new KeyValuePair <DatabaseEntry, KeyValuePair <
                                          DatabaseEntry, DatabaseEntry> >(pData,
                                                                          new KeyValuePair <DatabaseEntry, DatabaseEntry>(
                                                                              pKey, pData));
            cursor.Move(pair, true);
            Assert.IsTrue(cursor.MovePrevUnique());
            Assert.AreNotEqual(BitConverter.GetBytes((int)10),
                               cursor.Current.Key.Data);

            cursor.Close();
            secDB.Close();
            db.Close();
        }
Example #29
0
 /// <summary>
 /// Create a specialized join cursor for use in performing equality or
 /// natural joins on secondary indices.
 /// </summary>
 /// <remarks>
 /// <para>
 /// Once the cursors have been passed as part of <paramref name="lst"/>,
 /// they should not be accessed or modified until the newly created
 /// <see cref="JoinCursor"/>has been closed, or else inconsistent
 /// results may be returned.
 /// </para>
 /// <para>
 /// Joined values are retrieved by doing a sequential iteration over the
 /// first cursor in <paramref name="lst"/>, and a nested iteration over
 /// each secondary cursor in the order they are specified in the
 /// curslist parameter. This requires database traversals to search for
 /// the current datum in all the cursors after the first. For this
 /// reason, the best join performance normally results from sorting the
 /// cursors from the one that refers to the least number of data items
 /// to the one that refers to the most.
 /// </para>
 /// </remarks>
 /// <param name="lst">
 /// An array of SecondaryCursors. Each cursor must have been initialized
 /// to refer to the key on which the underlying database should be
 /// joined.
 /// </param>
 /// <param name="sortCursors">
 /// If true, sort the cursors from the one that refers to the least
 /// number of data items to the one that refers to the most.  If the
 /// data is structured so that cursors with many data items also share
 /// many common elements, higher performance results from listing
 /// those cursors before cursors with fewer data items; a sort
 /// order other than the default. A setting of false permits
 /// applications to perform join optimization prior to calling Join.
 /// </param>
 /// <returns>
 /// A specialized join cursor for use in performing equality or natural
 /// joins on secondary indices.
 /// </returns>
 public JoinCursor Join(SecondaryCursor[] lst, bool sortCursors)
 {
     int i;
     IntPtr[] cursList = new IntPtr[lst.Length + 1];
     for (i = 0; i < lst.Length; i++)
         cursList[i] = DBC.getCPtr(
             SecondaryCursor.getDBC(lst[i])).Handle;
     cursList[i] = IntPtr.Zero;
     return new JoinCursor(db.join(cursList,
         sortCursors ? 0 : DbConstants.DB_JOIN_NOSORT));
 }
Example #30
0
        public void TestJoin()
        {
            testName = "TestJoin";
            SetUpTest(true);
            string dbFileName = testHome + "/" + testName + ".db";
            string secFileName1 = testHome + "/" + "sec_" + testName + "1.db";
            string secFileName2 = testHome + "/" + "sec_" + testName + "2.db";

            // Open a primary database.
            BTreeDatabaseConfig dbCfg = new BTreeDatabaseConfig();
            dbCfg.Creation = CreatePolicy.IF_NEEDED;
            BTreeDatabase db = BTreeDatabase.Open(dbFileName, dbCfg);

            for (int i = 0; i < 10; i++)
                db.Put(new DatabaseEntry(BitConverter.GetBytes(i)),
                    new DatabaseEntry(BitConverter.GetBytes(i)));

            /*
             * Open two databases, their secondary databases and
             * secondary cursors.
             */
            SecondaryBTreeDatabase secDB1, secDB2;
            SecondaryCursor[] cursors = new SecondaryCursor[2];
            GetSecCursor(db, secFileName1,
                new SecondaryKeyGenDelegate(KeyGenOnBigByte),
                out secDB1, out cursors[0], false, null);
            GetSecCursor(db, secFileName2,
                new SecondaryKeyGenDelegate(KeyGenOnLittleByte),
                out secDB2, out cursors[1], true, null);

            // Get join cursor.
            JoinCursor joinCursor = db.Join(cursors, true);
            Assert.IsNotNull(joinCursor.GetEnumerator().Current);

            // Close all.
            joinCursor.Dispose();
            cursors[0].Close();
            cursors[1].Close();
            secDB1.Close();
            secDB2.Close();
            db.Close();
        }
Example #31
0
        public void TestDuplicate()
        {
            testName = "TestDuplicate";
            testHome = testFixtureHome + "/" + testName;
            string dbFileName    = testHome + "/" + testName + ".db";
            string dbSecFileName = testHome + "/" + testName +
                                   "_sec.db";

            Configuration.ClearDir(testHome);

            // Open a primary database.
            BTreeDatabaseConfig dbConfig =
                new BTreeDatabaseConfig();

            dbConfig.Creation = CreatePolicy.IF_NEEDED;
            BTreeDatabase db = BTreeDatabase.Open(
                dbFileName, dbConfig);

            // Open a secondary database.
            SecondaryBTreeDatabaseConfig secConfig =
                new SecondaryBTreeDatabaseConfig(db,
                                                 new SecondaryKeyGenDelegate(SecondaryKeyGen));

            secConfig.Creation   = CreatePolicy.IF_NEEDED;
            secConfig.Duplicates = DuplicatesPolicy.UNSORTED;
            SecondaryBTreeDatabase secDB =
                SecondaryBTreeDatabase.Open(dbSecFileName,
                                            secConfig);

            // Put a pair of key and data into the database.
            DatabaseEntry key, data;

            key = new DatabaseEntry(
                ASCIIEncoding.ASCII.GetBytes("key"));
            data = new DatabaseEntry(
                ASCIIEncoding.ASCII.GetBytes("data"));
            db.Put(key, data);

            // Create a cursor.
            SecondaryCursor cursor = secDB.SecondaryCursor();

            cursor.Move(key, true);

            // Duplicate the cursor.
            SecondaryCursor dupCursor;

            dupCursor = cursor.Duplicate(true);

            /*
             * Confirm that the duplicate cursor has the same
             * position as the original one.
             */
            Assert.AreEqual(cursor.Current.Key,
                            dupCursor.Current.Key);
            Assert.AreEqual(cursor.Current.Value,
                            dupCursor.Current.Value);

            // Close the cursor and the duplicate cursor.
            dupCursor.Close();
            cursor.Close();

            // Close secondary and primary database.
            secDB.Close();
            db.Close();
        }
Example #32
0
        public void TestMoveJoinCursor()
        {
            testName = "TestMoveJoinCursor";
            SetUpTest(true);
            string dbFileName = testHome + "/" + testName + ".db";
            string secFileName1 = testHome + "/" + "sec_" + testName + "1.db";
            string secFileName2 = testHome + "/" + "sec_" + testName + "2.db";

            // Open a primary database.
            BTreeDatabaseConfig dbCfg = new BTreeDatabaseConfig();
            dbCfg.Creation = CreatePolicy.IF_NEEDED;
            BTreeDatabase db = BTreeDatabase.Open(dbFileName, dbCfg);

            /*
             * Open a secondary database on high byte of
             * its data and another secondary database on
             * little byte of its data.
             */
            SecondaryBTreeDatabase secDB1, secDB2;
            SecondaryCursor[] cursors = new SecondaryCursor[2];
            byte[] byteValue = new byte[1];

            byteValue[0] = 0;
            GetSecCursor(db, secFileName1,
                new SecondaryKeyGenDelegate(KeyGenOnBigByte),
                out secDB1, out cursors[0], false,
                new DatabaseEntry(byteValue));

            byteValue[0] = 1;
            GetSecCursor(db, secFileName2,
                new SecondaryKeyGenDelegate(KeyGenOnLittleByte),
                out secDB2, out cursors[1], true,
                new DatabaseEntry(byteValue));

            // Get join cursor.
            JoinCursor joinCursor = db.Join(cursors, true);

            /*
             * MoveNextJoinItem do not use data value found
             * in all of the cursor so the data in Current won't be
             * changed.
             */
            Assert.IsTrue(joinCursor.MoveNextItem());
            Assert.AreEqual(0, joinCursor.Current.Key.Data[
                joinCursor.Current.Key.Data.Length - 1]);
            Assert.AreEqual(1, joinCursor.Current.Key.Data[0]);
            Assert.IsNull(joinCursor.Current.Value.Data);

            // Iterate on join cursor.
            foreach (KeyValuePair<DatabaseEntry, DatabaseEntry> pair in joinCursor)
            {
                /*
                 * Confirm that the key got by join cursor has 0 at
                 * its highest byte and 1 at its lowest byte.
                 */
                Assert.AreEqual(0, pair.Key.Data[pair.Key.Data.Length - 1]);
                Assert.AreEqual(1, pair.Key.Data[0]);
            }

            Assert.IsFalse(joinCursor.MoveNext());

            // Close all.
            joinCursor.Close();
            cursors[0].Close();
            cursors[1].Close();
            secDB1.Close();
            secDB2.Close();
            db.Close();
        }
Example #33
0
        public void TestJoin()
        {
            testName = "TestJoin";
            testHome = testFixtureHome + "/" + testName;
            string dbFileName = testHome + "/" + testName + ".db";
            string secFileName1 = testHome + "/" + "sec_" + testName + "1.db";
            string secFileName2 = testHome + "/" + "sec_" + testName + "2.db";

            Configuration.ClearDir(testHome);

            // Open a primary database.
            BTreeDatabaseConfig dbCfg = new BTreeDatabaseConfig();
            dbCfg.Creation = CreatePolicy.IF_NEEDED;
            BTreeDatabase db = BTreeDatabase.Open(dbFileName, dbCfg);

            /*
             * Open two databases, their secondary databases and
             * secondary cursors.
             */
            SecondaryBTreeDatabase secDB1, secDB2;
            SecondaryCursor[] cursors = new SecondaryCursor[2];
            GetSecCursor(db, secFileName1,
                new SecondaryKeyGenDelegate(KeyGenOnBigByte),
                out secDB1, out cursors[0], false, null);
            GetSecCursor(db, secFileName2,
                new SecondaryKeyGenDelegate(KeyGenOnLittleByte),
                out secDB2, out cursors[1], true, null);

            // Get join cursor.
            JoinCursor joinCursor = db.Join(cursors, true);

            // Close all.
            joinCursor.Close();
            cursors[0].Close();
            cursors[1].Close();
            secDB1.Close();
            secDB2.Close();
            db.Close();
        }
Example #34
0
        public void TestMoveJoinCursor()
        {
            testName = "TestMoveJoinCursor";
            SetUpTest(true);
            string dbFileName   = testHome + "/" + testName + ".db";
            string secFileName1 = testHome + "/" + "sec_" + testName + "1.db";
            string secFileName2 = testHome + "/" + "sec_" + testName + "2.db";

            // Open a primary database.
            BTreeDatabaseConfig dbCfg = new BTreeDatabaseConfig();

            dbCfg.Creation = CreatePolicy.IF_NEEDED;
            BTreeDatabase db = BTreeDatabase.Open(dbFileName, dbCfg);

            /*
             * Open a secondary database on high byte of
             * its data and another secondary database on
             * little byte of its data.
             */
            SecondaryBTreeDatabase secDB1, secDB2;

            SecondaryCursor[] cursors   = new SecondaryCursor[2];
            byte[]            byteValue = new byte[1];

            byteValue[0] = 0;
            GetSecCursor(db, secFileName1,
                         new SecondaryKeyGenDelegate(KeyGenOnBigByte),
                         out secDB1, out cursors[0], false,
                         new DatabaseEntry(byteValue));

            byteValue[0] = 1;
            GetSecCursor(db, secFileName2,
                         new SecondaryKeyGenDelegate(KeyGenOnLittleByte),
                         out secDB2, out cursors[1], true,
                         new DatabaseEntry(byteValue));

            // Get join cursor.
            JoinCursor joinCursor = db.Join(cursors, true);

            /*
             * MoveNextJoinItem do not use data value found
             * in all of the cursor so the data in Current won't be
             * changed.
             */
            Assert.IsTrue(joinCursor.MoveNextItem());
            Assert.AreEqual(0, joinCursor.Current.Key.Data[
                                joinCursor.Current.Key.Data.Length - 1]);
            Assert.AreEqual(1, joinCursor.Current.Key.Data[0]);
            Assert.IsNull(joinCursor.Current.Value.Data);

            // Iterate on join cursor.
            foreach (KeyValuePair <DatabaseEntry, DatabaseEntry> pair in joinCursor)
            {
                /*
                 * Confirm that the key got by join cursor has 0 at
                 * its highest byte and 1 at its lowest byte.
                 */
                Assert.AreEqual(0, pair.Key.Data[pair.Key.Data.Length - 1]);
                Assert.AreEqual(1, pair.Key.Data[0]);
            }

            Assert.IsFalse(joinCursor.MoveNext());

            // Close all.
            joinCursor.Close();
            cursors[0].Close();
            cursors[1].Close();
            secDB1.Close();
            secDB2.Close();
            db.Close();
        }