コード例 #1
0
ファイル: PageStoreTests.cs プロジェクト: Bikeman868/RestDB
        public void should_lock_pages()
        {
            const ulong pageNumber  = 1;
            const uint  pageOffset  = 10;
            const int   threadCount = 5;

            ThreadStart threadAction = () =>
            {
                var transaction = _database.BeginTransaction(null);
                _pageStore.BeginTransaction(transaction);

                _pageStore.Lock(transaction, pageNumber);

                Thread.Sleep(1);

                uint count;
                using (var page = _pageStore.Get(transaction, pageNumber, CacheHints.ForUpdate))
                    count = BitConverter.ToUInt32(page.Data, (int)pageOffset);

                Thread.Sleep(1);

                _pageStore.Update(
                    transaction, new[]
                {
                    new PageUpdate
                    {
                        PageNumber = pageNumber,
                        Offset     = pageOffset,
                        Data       = BitConverter.GetBytes(count + 1U)
                    }
                });

                _database.CommitTransaction(transaction);
                _pageStore.CommitTransaction(transaction);
                _pageStore.FinalizeTransaction(transaction);
            };

            var threads = new List <Thread>();

            for (var i = 0; i < threadCount; i++)
            {
                threads.Add(new Thread(threadAction));
            }

            foreach (var thread in threads)
            {
                thread.Start();
            }
            foreach (var thread in threads)
            {
                thread.Join();
            }

            var readTransaction = _database.BeginTransaction(null);

            _pageStore.BeginTransaction(readTransaction);

            using (var page = _pageStore.Get(readTransaction, pageNumber, CacheHints.None))
                Assert.AreEqual(threadCount, BitConverter.ToUInt32(page.Data, (int)pageOffset));
        }
コード例 #2
0
        PageLocation ISequentialRecordAccessor.Append(ulong firstPageNumber, ITransaction transaction, ulong recordSize)
        {
            if (recordSize == 0)
            {
                return(null);
            }

            // Find the last index page

            var indexPageNumber = firstPageNumber;

            while (true)
            {
                _pageStore.Lock(transaction, indexPageNumber);

                using (var indexPage = _pageStore.Get(transaction, indexPageNumber, CacheHints.MetaData | CacheHints.WithLock))
                {
                    var nextIndexPageNumber = BitConverter.ToUInt64(indexPage.Data, 0);
                    if (nextIndexPageNumber == 0UL)
                    {
                        break;
                    }
                    indexPageNumber = nextIndexPageNumber;
                }
            }

            var indexEntryOffset           = 8U;
            var lastRecordSize             = 0UL;
            var lastRecordEndingPageNumber = 0UL;
            var lastRecordBytesOnLastPage  = 0U;

            using (var lastIndexPage = _pageStore.Get(transaction, indexPageNumber, CacheHints.MetaData | CacheHints.WithLock))
            {
                while (lastIndexPage.Data[indexEntryOffset] != 0)
                {
                    var indexEntryType = lastIndexPage.Data[indexEntryOffset + 1];

                    if (indexEntryType == 1 || indexEntryType == 2)
                    {
                        // This is the start of a record
                        lastRecordSize = BitConverter.ToUInt64(lastIndexPage.Data, (int)indexEntryOffset + 2);
                        ulong lastRecordStartingPageNumber = BitConverter.ToUInt64(lastIndexPage.Data, (int)indexEntryOffset + 10);
                        uint  lastRecordOffset             = BitConverter.ToUInt32(lastIndexPage.Data, (int)indexEntryOffset + 18);
                        lastRecordBytesOnLastPage = (uint)((lastRecordSize + lastRecordOffset) % _pageSize);
                        ulong lastRecordPageCount = (lastRecordSize + lastRecordOffset + _pageSize - 1) / _pageSize;
                        lastRecordEndingPageNumber = lastRecordStartingPageNumber;
                    }
                    else if (indexEntryType == 3 && lastRecordSize != 0)
                    {
                        // This is a record continuation
                        var pageCount = lastIndexPage.Data[indexEntryOffset + 2];
                        lastRecordEndingPageNumber = BitConverter.ToUInt64(lastIndexPage.Data, (int)indexEntryOffset + 3 + (pageCount - 1) * 8);
                    }

                    // Find the last record and last index entry on this page

                    uint priorIndexEntryOffset = indexEntryOffset;
                    indexEntryOffset += lastIndexPage.Data[indexEntryOffset];
                }
            }

            var thisRecordStartingPageNumber = (lastRecordEndingPageNumber > 0 && lastRecordBytesOnLastPage < _pageSize)
                ? lastRecordEndingPageNumber
                : _pageStore.Allocate();

            var thisRecordOffset = thisRecordStartingPageNumber == lastRecordEndingPageNumber
                ? lastRecordBytesOnLastPage
                : 0U;

            var updates  = new List <PageUpdate>();
            var sequence = 1U;

            var additionalPageNumbers = AddRecordIndex(
                updates,
                ref sequence,
                indexPageNumber,
                indexEntryOffset,
                recordSize,
                thisRecordStartingPageNumber,
                thisRecordOffset);

            _pageStore.Update(transaction, updates);

            return(new PageLocation
            {
                PageStore = _pageStore,
                PageNumber = thisRecordStartingPageNumber,
                Offset = thisRecordOffset,
                Length = recordSize,
                ContunuationPages = additionalPageNumbers
            });
        }
コード例 #3
0
        PageLocation ISequentialRecordAccessor.Append(
            ulong firstPageNumber,
            ITransaction transaction,
            ulong recordSize)
        {
            if (recordSize == 0)
            {
                return(null);
            }

            var pageSize = _pageStore.PageSize;

            if (recordSize > pageSize)
            {
                throw new FileLayerException("Invalid attempt to write " + recordSize +
                                             " bytes into a page store with " + pageSize + " byte pages");
            }

            var updates  = new List <PageUpdate>();
            var sequence = 1U;

            PageLocation indexLocation = new PageLocation
            {
                PageStore  = _pageStore,
                PageNumber = firstPageNumber,
                Offset     = _indexPageHeadSize,
                Length     = _indexEntrySize
            };

            PageLocation recordLocation = new PageLocation
            {
                PageStore = _pageStore,
                Length    = recordSize
            };

            while (true)
            {
                _pageStore.Lock(transaction, indexLocation.PageNumber);

                using (var indexPage = _pageStore.Get(transaction, indexLocation.PageNumber, CacheHints.MetaData | CacheHints.WithLock))
                {
                    var nextIndexPageNumber = BitConverter.ToUInt64(indexPage.Data, 0);
                    if (nextIndexPageNumber == 0UL)
                    {
                        var nextIndexOffset = _indexPageHeadSize;
                        recordLocation.PageNumber = 0UL;

                        while (true)
                        {
                            var nextRecordPageNumber = BitConverter.ToUInt64(indexPage.Data, (int)nextIndexOffset);
                            var nextRecordOffset     = BitConverter.ToUInt32(indexPage.Data, (int)(nextIndexOffset + _pageNumberSize));

                            if (nextRecordPageNumber == 0UL)
                            {
                                indexLocation.Offset = nextIndexOffset;
                                break;
                            }

                            recordLocation.PageNumber = nextRecordPageNumber;
                            recordLocation.Offset     = nextRecordOffset;

                            nextIndexOffset += _indexEntrySize;

                            if (nextIndexOffset + _indexEntrySize > pageSize)
                            {
                                var newIndexPageNumber = _pageStore.Allocate();

                                updates.Add(new PageUpdate
                                {
                                    SequenceNumber = sequence++,
                                    PageNumber     = indexLocation.PageNumber,
                                    Offset         = 0U,
                                    Data           = BitConverter.GetBytes(newIndexPageNumber)
                                });

                                indexLocation.PageNumber = newIndexPageNumber;
                                indexLocation.Offset     = _indexPageHeadSize;

                                break;
                            }
                        }

                        break;
                    }
                    indexLocation.PageNumber = nextIndexPageNumber;
                }
            }

            if (recordLocation.PageNumber == 0UL || recordLocation.Offset + recordSize > pageSize)
            {
                recordLocation.PageNumber = _pageStore.Allocate();
                recordLocation.Offset     = 0U;
            }

            var newIndexEntry = new byte[_indexEntrySize];

            BitConverter.GetBytes(recordLocation.PageNumber).CopyTo(newIndexEntry, 0);
            BitConverter.GetBytes(recordLocation.Offset + (uint)recordSize).CopyTo(newIndexEntry, _pageNumberSize);

            updates.Add(new PageUpdate
            {
                SequenceNumber = sequence++,
                PageNumber     = indexLocation.PageNumber,
                Offset         = indexLocation.Offset,
                Data           = newIndexEntry
            });

            _pageStore.Update(transaction, updates);

            return(recordLocation);
        }