示例#1
0
        public async Task <LockingInfo> LockMultiple(params int[] indexes)
        {
            List <SemaphoreSlim> list = new List <SemaphoreSlim>();

            int mutual = indexes[0];

            for (int i = 1; i < indexes.Length; i++)
            {
                mutual ^= indexes[i];
            }
            SemaphoreSlim mutualSemaphore = lockItems.ElementAt(mutual % _maxCOncurrent);

            list.Add(mutualSemaphore);

            foreach (var index in indexes)
            {
                SemaphoreSlim semaphore = lockItems.ElementAt(index % _maxCOncurrent);
                await semaphore.WaitAsync(500).ConfigureAwait(false);

                list.Add(semaphore);
            }

            var lockingInfo = new LockingInfo()
            {
                semaphores = list
            };

            return(lockingInfo);
        }
示例#2
0
        /*
         * Move the cursor to the next duplicate record in
         * the database which has more than 2 duplicate
         * records. The returning value should be true.
         */
        public void MoveCursorToNextDuplicate(Cursor dbc,
                                              LockingInfo lck)
        {
            DatabaseEntry key = new DatabaseEntry(
                ASCIIEncoding.ASCII.GetBytes("key"));

            /*
             * The cursor should point to any record in the
             * database before it move to the next duplicate
             * record.
             */
            if (lck == null)
            {
                dbc.Move(key, true);
                Assert.IsTrue(dbc.MoveNextDuplicate());
            }
            else
            {
                /*
                 * Both the move and move next duplicate
                 * operation should use LockingInfo. If any
                 * one doesn't use LockingInfo, deadlock still
                 * occurs.
                 */
                dbc.Move(key, true, lck);
                Assert.IsTrue(dbc.MoveNextDuplicate(lck));
            }
        }
示例#3
0
        public void RdMfWt()
        {
            Transaction txn = paramEnv.BeginTransaction();
            BTreeCursor dbc = paramDB.Cursor(txn);

            try
            {
                LockingInfo lck = new LockingInfo();
                lck.ReadModifyWrite = true;

                // Read record.
                btCursorFunc(dbc, lck);

                // Block the current thread until event is set.
                signal.WaitOne();

                // Write new records into database.
                DatabaseEntry key  = new DatabaseEntry(BitConverter.GetBytes(55));
                DatabaseEntry data = new DatabaseEntry(BitConverter.GetBytes(55));
                dbc.Add(new KeyValuePair <DatabaseEntry, DatabaseEntry>(key, data));

                dbc.Close();
                txn.Commit();
            }
            catch (DeadlockException)
            {
                dbc.Close();
                txn.Abort();
            }
        }
示例#4
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();
        }
示例#6
0
        /// <summary>
        /// 获取值
        /// </summary>
        /// <param name="key"></param>
        /// <param name="info"></param>
        /// <param name="txn"></param>
        /// <returns></returns>
        public byte[] Get(byte[] key, LockingInfo info = null, Transaction txn = null)
        {
            DatabaseEntry k = new DatabaseEntry(key);
            KeyValuePair <DatabaseEntry, DatabaseEntry> pair = db.Get(k, txn, info);

            byte[] tmp = new byte[pair.Value.Data.Length];
            Array.Copy(pair.Value.Data, tmp, tmp.Length);
            pair.Key.Dispose();
            pair.Value.Dispose();
            return(tmp);
        }
示例#7
0
 /*
  * Move the cursor to last record in a nonempty
  * database. The returning value should be true.
  */
 public void MoveCursorToLast(Cursor dbc, LockingInfo lck)
 {
     if (lck == null)
     {
         Assert.IsTrue(dbc.MoveLast());
     }
     else
     {
         Assert.IsTrue(dbc.MoveLast(lck));
     }
 }
示例#8
0
        //public Dictionary<byte[], byte[]> GetMult(List<byte[]> keys, LockingInfo info = null, Transaction txn = null)
        //{
        //    Dictionary<byte[], byte[]> result = new Dictionary<byte[], byte[]>();
        //    // List<KeyValuePair<DatabaseEntry, DatabaseEntry>> lst = new List<KeyValuePair<DatabaseEntry, DatabaseEntry>>();
        //    List<DatabaseEntry> lst = new List<DatabaseEntry>();
        //    foreach (byte[] key in keys)
        //    {
        //        DatabaseEntry k = new DatabaseEntry(key);

        //        lst.Add(k);
        //    }
        //    MultipleDatabaseEntry multiple = new MultipleDatabaseEntry(lst, false);
        //    KeyValuePair<DatabaseEntry,DatabaseEntry> kv= db.Get(multiple);

        //    return result;
        //}

        /// <summary>
        ///取出多个值
        /// </summary>
        /// <param name="keys"></param>
        /// <param name="info"></param>
        /// <param name="txn"></param>
        /// <returns></returns>
        public Dictionary <byte[], byte[]> GetMultiple(List <byte[]> keys, LockingInfo info = null, Transaction txn = null)
        {
            Dictionary <byte[], byte[]> result = new Dictionary <byte[], byte[]>();

            foreach (byte[] key in keys)
            {
                DatabaseEntry k = new DatabaseEntry(key);
                KeyValuePair <DatabaseEntry, MultipleDatabaseEntry> pair = db.GetMultiple(k, bufferSize, txn, info);
                result[key] = pair.Value.Data;
            }
            return(result);
        }
示例#9
0
 /*
  * Move the cursor to the next record in the database
  * with more than five records. The returning values of
  * every move operation should be true.
  */
 public void MoveCursorToNext(Cursor dbc, LockingInfo lck)
 {
     for (int i = 0; i < 5; i++)
     {
         if (lck == null)
         {
             Assert.IsTrue(dbc.MoveNext());
         }
         else
         {
             Assert.IsTrue(dbc.MoveNext(lck));
         }
     }
 }
示例#10
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();
        }
示例#11
0
 /*
  * Move the cursor according to recno. The recno
  * starts from 1 and is increased by 1.
  */
 public void MoveCursorToRecno(BTreeCursor cursor,
                               LockingInfo lck)
 {
     for (uint i = 1; i <= 5; i++)
     {
         if (lck == null)
         {
             Assert.IsTrue(cursor.Move(i));
         }
         else
         {
             Assert.IsTrue(cursor.Move(i, lck));
         }
     }
 }
示例#12
0
 /*
  * Move the cursor to previous unique record in a
  * database with more than 2 records. The returning
  * value should be true.
  */
 public void MoveCursorToPrevUnique(Cursor dbc,
                                    LockingInfo lck)
 {
     for (int i = 0; i < 5; i++)
     {
         if (lck == null)
         {
             dbc.MovePrevUnique();
         }
         else
         {
             dbc.MovePrevUnique(lck);
         }
     }
 }
示例#13
0
        /// <summary>
        /// 获取多个值
        /// </summary>
        /// <param name="keys"></param>
        /// <param name="info"></param>
        /// <param name="txn"></param>
        /// <returns></returns>
        public Dictionary <byte[], byte[]> Get(List <byte[]> keys, LockingInfo info = null, Transaction txn = null)
        {
            Dictionary <byte[], byte[]> result = new Dictionary <byte[], byte[]>();

            foreach (byte[] key in keys)
            {
                DatabaseEntry k = new DatabaseEntry(key);
                KeyValuePair <DatabaseEntry, DatabaseEntry> pair = db.GetBoth(k, null, txn, info);
                byte[] tmp = new byte[pair.Value.Data.Length];
                Array.Copy(pair.Value.Data, tmp, tmp.Length);
                result[key] = tmp;
                pair.Key.Dispose();
                pair.Value.Dispose();
            }
            return(result);
        }
示例#14
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();
        }
示例#15
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();
        }
示例#16
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();
        }
        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();
        }
示例#18
0
 /*
  * Move the cursor to a duplicate record and then to
  * another duplicate one. And finally move to it previous
  * one. Since the previous duplicate one exist, the return
  * value of move previous duplicate record should be
  * true;
  */
 public void MoveCursorToPrevDuplicate(Cursor dbc,
                                       LockingInfo lck)
 {
     if (lck == null)
     {
         dbc.Move(new DatabaseEntry(
                      ASCIIEncoding.ASCII.GetBytes("key")), true);
         dbc.MoveNextDuplicate();
         Assert.IsTrue(dbc.MovePrevDuplicate());
     }
     else
     {
         dbc.Move(new DatabaseEntry(
                      ASCIIEncoding.ASCII.GetBytes("key")), true, lck);
         dbc.MoveNextDuplicate(lck);
         Assert.IsTrue(dbc.MovePrevDuplicate(lck));
     }
 }
示例#19
0
        /*
         * Move the cursor to an exisiting key and key/data
         * pair with LockingInfo.
         */
        public void MoveCursor(Cursor dbc, LockingInfo lck)
        {
            DatabaseEntry key, data;
            KeyValuePair <DatabaseEntry, DatabaseEntry> pair;

            key = new DatabaseEntry(
                BitConverter.GetBytes((int)0));
            data = new DatabaseEntry(
                BitConverter.GetBytes((int)0));
            pair = new KeyValuePair <DatabaseEntry,
                                     DatabaseEntry>(key, data);

            // Move to an existing key.
            Assert.IsTrue(dbc.Move(key, true, lck));

            // Move to an existing key/data pair.
            Assert.IsTrue(dbc.Move(pair, true, lck));
        }
        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();
        }
示例#21
0
 /*
  * Move the cursor to previous record in the database.
  * The returning value should be true;
  */
 public void MoveCursorToPrev(Cursor dbc,
                              LockingInfo lck)
 {
     if (lck == null)
     {
         dbc.MoveLast();
         for (int i = 0; i < 5; i++)
         {
             Assert.IsTrue(dbc.MovePrev());
         }
     }
     else
     {
         dbc.MoveLast(lck);
         for (int i = 0; i < 5; i++)
         {
             Assert.IsTrue(dbc.MovePrev(lck));
         }
     }
 }
示例#22
0
 /*l
  * Move the cursor according to a given recno and
  * return the current record's recno. The given recno
  * and the one got from the cursor should be the same.
  */
 public void ReturnRecno(BTreeCursor cursor,
                         LockingInfo lck)
 {
     for (uint i = 1; i <= 5; i++)
     {
         if (lck == null)
         {
             if (cursor.Move(i) == true)
             {
                 Assert.AreEqual(i, cursor.Recno());
             }
         }
         else
         {
             if (cursor.Move(i, lck) == true)
             {
                 Assert.AreEqual(i, cursor.Recno(lck));
             }
         }
     }
 }
示例#23
0
        /*
         * Move the cursor to current existing record. The returning
         * value should be true.
         */
        public void MoveCursorToCurrentRec(Cursor dbc,
                                           LockingInfo lck)
        {
            // Add a record to the database.
            KeyValuePair <DatabaseEntry, DatabaseEntry> pair;

            pair = new KeyValuePair <DatabaseEntry, DatabaseEntry>(
                new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("key")),
                new DatabaseEntry(ASCIIEncoding.ASCII.GetBytes("key")));
            dbc.Add(pair);

            if (lck == null)
            {
                dbc.Refresh();
            }
            else
            {
                dbc.Refresh(lck);
            }

            Assert.IsNotNull(dbc.Current.Key);
        }
示例#24
0
 public SharedResourceTransactionItem(LockingInfo lockingInfo)
 {
     this.lockingInfo = lockingInfo;
 }
示例#25
0
        public void TestMoveNextMultipleKey()
        {
            testName = "TestMoveNextMultipleKey";
            SetUpTest(true);

            BTreeDatabase       db;
            BTreeCursor         cursor;
            DatabaseEnvironment env;
            Transaction         txn;
            int cnt = 0;

            BTreeDatabaseConfig dbConfig = new BTreeDatabaseConfig();

            dbConfig.Creation   = CreatePolicy.ALWAYS;
            dbConfig.Duplicates = DuplicatesPolicy.UNSORTED;

            GetMultipleDB(testHome, testName + ".db", dbConfig,
                          out env, out txn, out db, out cursor);

            /*
             * Position the cursor to the first record, and bulk get
             * all other records.
             */
            Assert.True(cursor.MoveFirst());
            Assert.True(cursor.MoveNextMultipleKey());
            MultipleKeyDatabaseEntry pairs =
                cursor.CurrentMultipleKey;

            foreach (KeyValuePair <DatabaseEntry, DatabaseEntry> p
                     in pairs)
            {
                cnt++;
            }
            Assert.AreEqual(cnt, 100);

            // Bulk read uncommitted records.
            cnt = 0;
            LockingInfo lockingInfo = new LockingInfo();

            Assert.True(cursor.MoveFirst(lockingInfo));
            lockingInfo.IsolationDegree = Isolation.DEGREE_ONE;
            Assert.True(cursor.MoveNextMultipleKey(lockingInfo));
            pairs = cursor.CurrentMultipleKey;
            foreach (KeyValuePair <DatabaseEntry, DatabaseEntry> p
                     in pairs)
            {
                cnt++;
            }
            Assert.AreEqual(cnt, 100);

            cursor.Dispose();
            txn.Commit();

            /*
             * Insert duplicate records of the key in the last
             * record.
             */
            txn    = env.BeginTransaction();
            cursor = db.Cursor(txn);
            Assert.IsTrue(cursor.MoveLast());
            DatabaseEntry key = cursor.Current.Key;

            for (int i = 200; i < 800; i++)
            {
                cursor.Insert(new DatabaseEntry(
                                  BitConverter.GetBytes(i)),
                              Cursor.InsertLocation.AFTER);
            }

            /*
             * Move to the first duplicate records, and bulk read
             * all duplicate ones.
             */
            cnt = 0;
            Assert.True(cursor.Move(key, true));
            while (cursor.MoveNextDuplicateMultipleKey(
                       (int)db.Pagesize))
            {
                pairs = cursor.CurrentMultipleKey;
                foreach (KeyValuePair <
                             DatabaseEntry, DatabaseEntry> p in pairs)
                {
                    Assert.AreEqual(key.Data, p.Key.Data);
                    cnt++;
                }
            }
            Assert.AreEqual(cnt, 600);

            cursor.Close();
            db.Close();
            txn.Commit();
            env.Close();
        }
 protected override void _lockService_AddItem(UserIdentity sender, ObjectKey key, LockingInfo value)
 {
     if (_notifier != null)
         _notifier.ObjectLocked(value);
 }