Exemple #1
0
        private void DoDisposeNode(NodeId id)
        {
            // If the node is a special node, then we don't dispose it
            if (id.IsSpecial)
            {
                return;
            }

            // Is 'id' a leaf node?
            IMutableArea nodeArea = nodeStore.GetMutableArea(ToInt64StoreAddress(id));

            // Are we a leaf?
            nodeArea.Position = 0;
            int nodeType = nodeArea.ReadInt2();

            if (nodeType == StoreLeafType)
            {
                // Yes, get its reference_count,
                lock (referenceCountLock) {
                    nodeArea.Position = 4;
                    int refCount = nodeArea.ReadInt4();
                    // If the reference_count is >1 then decrement it and return
                    if (refCount > 1)
                    {
                        nodeArea.Position = 4;
                        nodeArea.WriteInt4(refCount - 1);
                        return;
                    }
                }
            }
            else if (nodeType != StoreBranchType)
            {
                // Has to be a branch type, otherwise failure
                throw new IOException("Unknown node type.");
            }
            // 'id' is a none leaf branch or its reference count is 1, so delete the
            // area.

            // NOTE, we delete from the cache first before we delete the area
            //   because the deleted area may be reclaimed immediately and deleting
            //   from the cache after may be too late.

            // Delete from the cache because the given ref may be recycled for a new
            // node at some point.
            lock (branchCache) {
                branchCache.Remove(id);
            }

            // Delete the area
            nodeStore.DeleteArea(ToInt64StoreAddress(id));
        }
Exemple #2
0
        public bool LinkLeaf(Key key, NodeId id)
        {
            // If the node is a special node, then we don't need to reference count it.
            if (id.IsSpecial)
            {
                return(true);
            }
            try {
                nodeStore.LockForWrite();

                // Get the area as a MutableArea object
                IMutableArea leafArea = nodeStore.GetMutableArea(ToInt64StoreAddress(id));
                // We synchronize over a reference count lock
                // (Pending: should we lock by area instead?  I'm not sure it will be
                //  worth the complexity of a more fine grained locking mechanism for the
                //  performance improvements - maybe we should implement a locking
                //  mechanism inside MutableArea).
                lock (referenceCountLock) {
                    // Assert this is a leaf
                    leafArea.Position = 0;
                    short nodeType = leafArea.ReadInt2();
                    if (nodeType != StoreLeafType)
                    {
                        throw new IOException("Can only link to a leaf node.");
                    }

                    leafArea.Position = 4;
                    int refCount = leafArea.ReadInt4();
                    // If reference counter is near overflowing, return false.
                    if (refCount > Int32.MaxValue - 8)
                    {
                        return(false);
                    }

                    leafArea.Position = 4;
                    leafArea.WriteInt4(refCount + 1);
                }
                return(true);
            } finally {
                nodeStore.UnlockForWrite();
            }
        }
Exemple #3
0
        public bool Start()
        {
            lock (lockObject) {
                treeSystem = new StoreTreeSystem(store, branchNodeSize, leafNodeSize, heapNodeCacheSize, branchNodeCacheSize);
                treeSystem.Create();
                treeSystem.CheckPoint();

                // The actual database
                StoreTreeSystem treeStore;

                // Get the header area
                IArea headerArea = store.GetArea(-1);
                int   magicValue = headerArea.ReadInt4();
                // If header area magic value is zero, then we assume this is a brand
                // new database and initialize it with the configuration information
                // given.
                if (magicValue == 0)
                {
                    // Create a tree store inside the file store,
                    treeStore = new StoreTreeSystem(store, branchNodeSize, leafNodeSize, heapNodeCacheSize,
                                                    branchNodeCacheSize);
                    // Create the tree and returns a pointer to the tree,
                    long treePointer = treeStore.Create();

                    // Create an area object with state information about the tree
                    IAreaWriter awriter = store.CreateArea(128);
                    awriter.WriteInt4(0x0101);                     // The version value
                    awriter.WriteInt8(treePointer);
                    awriter.WriteInt4(branchNodeSize);
                    awriter.WriteInt4(leafNodeSize);
                    awriter.Finish();
                    long         dummy = awriter.Id;
                    IMutableArea harea = store.GetMutableArea(-1);
                    harea.WriteInt4(0x092BA001);                     // The magic value
                    harea.WriteInt8(awriter.Id);
                    harea.CheckOut();
                }
                else if (magicValue == 0x092BA001)
                {
                    long apointer = headerArea.ReadInt8();
                    // The area that contains configuration details,
                    IArea initArea = store.GetArea(apointer);
                    int   version  = initArea.ReadInt4();
                    if (version != 0x0101)
                    {
                        throw new IOException("Unknown version in tree initialization area");
                    }

                    // Read the pointer to the tree store
                    long treePointer = initArea.ReadInt8();
                    // Read the branch and leaf node sizes as set when the database was
                    // created.
                    int ibranchNodeSize = initArea.ReadInt4();
                    int ileafNodeSize   = initArea.ReadInt4();

                    // Create the tree store
                    treeStore = new StoreTreeSystem(store, ibranchNodeSize, ileafNodeSize, heapNodeCacheSize,
                                                    branchNodeCacheSize);
                    // Initialize the tree
                    treeStore.Init(treePointer);
                }
                else
                {
                    throw new IOException("Data is corrupt, invalid magic value in store");
                }

                // Set the point of the tree store
                treeStore.CheckPoint();

                // Set up final internal state and return true
                treeSystem      = treeStore;
                databaseStarted = true;
                return(true);
            }
        }
Exemple #4
0
        private void DisposeOldVersions()
        {
            List <object> disposeList = new List <object>();

            lock (versions) {
                // size - 1 because we don't want to delete the very last version,
                int  sz = versions.Count - 1;
                bool foundLockedEntry = false;
                for (int i = 0; i < sz && foundLockedEntry == false; ++i)
                {
                    VersionInfo vinfo = versions[i];
                    // If this version isn't locked,
                    if (vinfo.NotLocked)
                    {
                        // Add to the dispose list
                        disposeList.Add(vinfo);
                        // And delete from the versions list,
                        versions.RemoveAt(i);
                        --sz;
                        --i;
                    }
                    else
                    {
                        // If it is locked, we exit the loop
                        foundLockedEntry = true;
                    }
                }
            }

            // If there are entries to dispose?
            if (disposeList.Count > 0)
            {
                // We synchronize here to ensure the versions list can't be modified by
                // a commit operation while we are disposing this.
                lock (this) {
                    // Run within a write lock on the store
                    try {
                        nodeStore.LockForWrite();

                        // First we write out a modified version header minus the versions we
                        // are to delete,

                        // Get the current version list
                        IMutableArea headerArea = nodeStore.GetMutableArea(headerId);
                        headerArea.Position = 8;

                        long versionListId = headerArea.ReadInt8();

                        // Read information from the old version info,
                        IArea versionListArea = nodeStore.GetArea(versionListId);
                        versionListArea.ReadInt4();                         // The magic

                        int versionCount = versionListArea.ReadInt4();


                        int newVersionCount = versionCount - disposeList.Count;
                        // Create a new list,
                        IAreaWriter newVersionList = nodeStore.CreateArea(8 + (8 * newVersionCount));
                        newVersionList.WriteInt4(0x01433);
                        newVersionList.WriteInt4(newVersionCount);
                        // Skip the versions we are deleting,
                        for (int i = 0; i < disposeList.Count; ++i)
                        {
                            versionListArea.ReadInt8();
                        }
                        // Now copy the list from the new point
                        for (int i = 0; i < newVersionCount; ++i)
                        {
                            newVersionList.WriteInt8(versionListArea.ReadInt8());
                        }
                        newVersionList.Finish();

                        // Write the new area to the header,
                        headerArea.Position = 8;
                        headerArea.WriteInt8(newVersionList.Id);

                        // Delete the old version list Area,
                        nodeStore.DeleteArea(versionListId);

                        // Dispose the version info,
                        int sz = disposeList.Count;
                        for (int i = 0; i < sz; ++i)
                        {
                            VersionInfo vinfo       = (VersionInfo)disposeList[i];
                            long        vRef        = vinfo.VersionInfoRef;
                            IArea       versionArea = nodeStore.GetArea(vRef);
                            int         magic       = versionArea.ReadInt4();
                            int         rev         = versionArea.ReadInt4();
                            // Check the magic,
                            if (magic != 0x04EA23)
                            {
                                throw new ApplicationException("Magic value for version area is incorrect.");
                            }

                            long verId   = versionArea.ReadInt8();
                            long nrnHigh = versionArea.ReadInt8();
                            long nrnLow  = versionArea.ReadInt8();

                            int nodeCount = versionArea.ReadInt4();
                            // For each node,
                            for (int n = 0; n < nodeCount; ++n)
                            {
                                // Read the next area
                                long   drnHigh   = versionArea.ReadInt8();
                                long   drnLow    = versionArea.ReadInt8();
                                NodeId delNodeId = new NodeId(drnHigh, drnLow);
                                // Cleanly disposes the node
                                DoDisposeNode(delNodeId);
                            }

                            // Delete the node header,
                            nodeStore.DeleteArea(vRef);
                        }
                    } finally {
                        nodeStore.UnlockForWrite();
                    }
                }
            }
        }
Exemple #5
0
        private long WriteVersionsList(long versionId, TreeSystemTransaction tran)
        {
            lock (this) {
                // Write the version info and the deleted refs to a new area,
                NodeId rootNodeId = tran.RootNodeId;
                if (rootNodeId.IsInMemory)
                {
                    throw new ApplicationException("Assertion failed, root_node is on heap.");
                }

                // Get the list of all nodes deleted in the transaction
                List <NodeId> deletedRefs = tran.NodeDeletes;
                // Sort it
                deletedRefs.Sort();
                // Check for any duplicate entries (we shouldn't double delete stuff).
                for (int i = 1; i < deletedRefs.Count; ++i)
                {
                    if (deletedRefs[i - 1].Equals(deletedRefs[i]))
                    {
                        // Oops, duplicated delete
                        throw new ApplicationException("PRAGMATIC_CHECK failed: duplicate records in delete list.");
                    }
                }


                long theVersionId = WriteSingleVersionInfo(versionId, rootNodeId, deletedRefs);

                // Now update the version list by copying the list and adding the new ref
                // to the end.

                // Get the current version list
                IMutableArea headerArea = nodeStore.GetMutableArea(headerId);
                headerArea.Position = 8;

                long versionListId = headerArea.ReadInt8();

                // Read information from the old version info,
                IArea versionListArea = nodeStore.GetArea(versionListId);
                versionListArea.ReadInt4();                 // The magic
                int versionCount = versionListArea.ReadInt4();

                // Create a new list,
                IAreaWriter newVersionList = nodeStore.CreateArea(8 + (8 * (versionCount + 1)));
                newVersionList.WriteInt4(0x01433);
                newVersionList.WriteInt4(versionCount + 1);
                for (int i = 0; i < versionCount; ++i)
                {
                    newVersionList.WriteInt8(versionListArea.ReadInt8());
                }
                newVersionList.WriteInt8(theVersionId);
                newVersionList.Finish();

                // Write the new area to the header,
                headerArea.Position = 8;
                headerArea.WriteInt8(newVersionList.Id);

                // Delete the old version list Area,
                nodeStore.DeleteArea(versionListId);

                // Done,
                return(theVersionId);
            }
        }
Exemple #6
0
        public bool Start()
        {
            lock (lockObject) {
                // We can't start a database that is already started,
                if (databaseStarted || treeSystem != null)
                {
                    return(false);
                }

                // Make a data.koi file with a single TreeSystem structure mapped into it
                const string fileExt    = "cdb";
                const string dbFileName = "data";

                bufferManager = new LoggingBufferManager(path, path, false, maxPageCount, pageSize, fileExt, fileRolloverSize,
                                                         logger, true);
                bufferManager.Start();

                // The backing store
                fileStore = new JournalledFileStore(dbFileName, bufferManager, false);
                fileStore.Open();

                // The actual database
                StoreTreeSystem treeStore;

                // Get the header area
                IArea headerArea = fileStore.GetArea(-1);
                int   magicValue = headerArea.ReadInt4();
                // If header area magic value is zero, then we assume this is a brand
                // new database and initialize it with the configuration information
                // given.
                if (magicValue == 0)
                {
                    // Create a tree store inside the file store,
                    treeStore = new StoreTreeSystem(fileStore, branchNodeSize, leafNodeSize, heapNodeCacheSize,
                                                    branchNodeCacheSize);
                    // Create the tree and returns a pointer to the tree,
                    long treePointer = treeStore.Create();

                    // Create an area object with state information about the tree
                    IAreaWriter awriter = fileStore.CreateArea(128);
                    awriter.WriteInt4(0x0101);                     // The version value
                    awriter.WriteInt8(treePointer);
                    awriter.WriteInt4(branchNodeSize);
                    awriter.WriteInt4(leafNodeSize);
                    awriter.Finish();
                    long         dummy = awriter.Id;
                    IMutableArea harea = fileStore.GetMutableArea(-1);
                    harea.WriteInt4(0x092BA001);                     // The magic value
                    harea.WriteInt8(awriter.Id);
                    harea.CheckOut();
                }
                else if (magicValue == 0x092BA001)
                {
                    long apointer = headerArea.ReadInt8();
                    // The area that contains configuration details,
                    IArea initArea = fileStore.GetArea(apointer);
                    int   version  = initArea.ReadInt4();
                    if (version != 0x0101)
                    {
                        throw new IOException("Unknown version in tree initialization area");
                    }

                    // Read the pointer to the tree store
                    long treePointer = initArea.ReadInt8();
                    // Read the branch and leaf node sizes as set when the database was
                    // created.
                    int ibranchNodeSize = initArea.ReadInt4();
                    int ileafNodeSize   = initArea.ReadInt4();

                    // Create the tree store
                    treeStore = new StoreTreeSystem(fileStore, ibranchNodeSize, ileafNodeSize, heapNodeCacheSize,
                                                    branchNodeCacheSize);
                    // Initialize the tree
                    treeStore.Init(treePointer);
                }
                else
                {
                    throw new IOException("Data is corrupt, invalid magic value in store");
                }

                // Set the point of the tree store
                treeStore.CheckPoint();

                // Set up final internal state and return true
                treeSystem      = treeStore;
                databaseStarted = true;
                return(true);
            }
        }