Beispiel #1
0
        /// <summary>
        /// Remove a mapping from a document GUID.
        /// The page chain is not affected.
        /// If no such document id is bound, nothing happens
        /// </summary>
        public void UnbindIndex(Guid documentId)
        {
            lock (_fslock)
            {
                var indexLink = GetIndexPageLink();
                if (!indexLink.TryGetLink(0, out var indexTopPageId))
                {
                    return;  // no index to unbind
                }

                // Search for the binding, and remove if found
                var currentPage = GetRawPage(indexTopPageId);
                while (currentPage != null)
                {
                    var indexSnap = new IndexPage();
                    indexSnap.Defrost(currentPage.BodyStream());

                    var found = indexSnap.Remove(documentId);
                    if (found)
                    {
                        var stream = indexSnap.Freeze();
                        currentPage.Write(stream, 0, stream.Length);
                        CommitPage(currentPage);
                        Flush();
                        return;
                    }

                    currentPage = GetRawPage(currentPage.PrevPageId);
                }
            }
        }
Beispiel #2
0
        /// <summary>
        /// Get the top page ID for a document ID by reading the index.
        /// If the document ID can't be found, returns -1
        /// </summary>
        public int GetDocumentHead(Guid documentId)
        {
            var indexLink = GetIndexPageLink();

            if (!indexLink.TryGetLink(0, out var indexTopPageId))
            {
                indexTopPageId = -1;
            }

            // Try to update an existing document
            var currentPage = GetRawPage(indexTopPageId);

            while (currentPage != null)
            {
                var indexSnap = new IndexPage();
                indexSnap.Defrost(currentPage.BodyStream());

                var found = indexSnap.Search(documentId, out var link);
                if (found && link != null)
                {
                    if (link.TryGetLink(0, out var result))
                    {
                        return(result);
                    }
                }

                currentPage = GetRawPage(currentPage.PrevPageId);
            }
            return(-1);
        }
Beispiel #3
0
        /// <summary>
        /// Map a document GUID to a page ID.
        /// If the document has an existing page, the versions will be incremented.
        /// If a version expires, the page ID will be returned in `expiredPageId`
        /// </summary>
        /// <param name="documentId">Unique ID for the document</param>
        /// <param name="newPageId">top page id for most recent version of the document</param>
        /// <param name="expiredPageId">an expired version of the document, or `-1` if no versions have expired</param>
        public void BindIndex(Guid documentId, int newPageId, out int expiredPageId)
        {
            lock (_fslock)
            {
                var indexLink = GetIndexPageLink();
                if (!indexLink.TryGetLink(0, out var indexTopPageId))
                {
                    indexTopPageId = -1;
                }

                // Try to update an existing document
                var currentPage = GetRawPage(indexTopPageId);
                while (currentPage != null)
                {
                    var indexSnap = new IndexPage();
                    indexSnap.Defrost(currentPage.BodyStream());

                    var found = indexSnap.Update(documentId, newPageId, out expiredPageId);
                    if (found)
                    {
                        var stream = indexSnap.Freeze();
                        currentPage.Write(stream, 0, stream.Length);
                        CommitPage(currentPage);
                        return;
                    }

                    currentPage = GetRawPage(currentPage.PrevPageId);
                }

                // Try to insert a new link in an existing index page
                expiredPageId = -1;
                currentPage   = GetRawPage(indexTopPageId);
                while (currentPage != null)
                {
                    var indexSnap = new IndexPage();
                    indexSnap.Defrost(currentPage.BodyStream());

                    var found = indexSnap.TryInsert(documentId, newPageId);
                    if (found)
                    {
                        var stream = indexSnap.Freeze();
                        currentPage.Write(stream, 0, stream.Length);
                        CommitPage(currentPage);
                        return;
                    }

                    currentPage = GetRawPage(currentPage.PrevPageId);
                }

                // need to extend into a new index, and write to a new version of the head
                var newIndex = new IndexPage();
                var ok       = newIndex.TryInsert(documentId, newPageId);
                if (!ok)
                {
                    throw new Exception("Failed to write index to blank index page");
                }
                var slot = new int[1];
                AllocatePageBlock(slot);
                var newPage = GetRawPage(slot[0]) ?? throw new Exception("Failed to read newly allocated page");
                newPage.PrevPageId = indexTopPageId;
                var newStream = newIndex.Freeze();
                newPage.Write(newStream, 0, newStream.Length);
                CommitPage(newPage);

                // set new head link
                indexLink.WriteNewLink(newPage.PageId, out _); // Index is always extended, we never clean it up
                SetIndexPageLink(indexLink);
                Flush();
            }
        }