Example #1
0
        private long WriteSingleVersionInfo(long versionId, NodeId rootNodeId, List <NodeId> deletedRefs)
        {
            int deletedRefCount = deletedRefs.Count;

            // Write the version info and the deleted refs to a new area,
            IAreaWriter writer = nodeStore.CreateArea(4 + 4 + 8 + 8 + 8 + 4 + (deletedRefCount * 16));

            writer.WriteInt4(0x04EA23);
            writer.WriteInt4(1);
            writer.WriteInt8(versionId);
            writer.WriteInt8(rootNodeId.High);
            writer.WriteInt8(rootNodeId.Low);

            writer.WriteInt4(deletedRefCount);
            foreach (NodeId deletedNode in deletedRefs)
            {
                writer.WriteInt8(deletedNode.High);
                writer.WriteInt8(deletedNode.Low);
            }

            writer.Finish();

            return(writer.Id);
        }
Example #2
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);
            }
        }
Example #3
0
        public IList <NodeId> Persist(TreeWrite write)
        {
            try {
                nodeStore.LockForWrite();

                IList <ITreeNode> allBranches = write.BranchNodes;
                IList <ITreeNode> allLeafs    = write.LeafNodes;
                List <ITreeNode>  nodes       = new List <ITreeNode>(allBranches.Count + allLeafs.Count);
                nodes.AddRange(allBranches);
                nodes.AddRange(allLeafs);

                // The list of nodes to be allocated,
                int sz = nodes.Count;
                // The list of allocated referenced for the nodes,
                NodeId[] refs = new NodeId[sz];
                // The list of area writers,
                IAreaWriter[] writers = new IAreaWriter[sz];

                // Allocate the space first,
                for (int i = 0; i < sz; ++i)
                {
                    ITreeNode node = nodes[i];
                    // Is it a branch node?
                    if (node is TreeBranch)
                    {
                        TreeBranch branch = (TreeBranch)node;
                        int        ndsz   = branch.NodeDataSize;
                        writers[i] = nodeStore.CreateArea(4 + 4 + (ndsz * 8));
                    }
                    // Otherwise, it must be a leaf node,
                    else
                    {
                        TreeLeaf leaf = (TreeLeaf)node;
                        int      lfsz = leaf.Length;
                        writers[i] = nodeStore.CreateArea(12 + lfsz);
                    }
                    // Set the reference,
                    refs[i] = FromInt64StoreAddress(writers[i].Id);
                }

                // Now write out the data,
                for (int i = 0; i < sz; ++i)
                {
                    ITreeNode node = nodes[i];
                    // Is it a branch node?
                    if (node is TreeBranch)
                    {
                        TreeBranch branch = (TreeBranch)node;

                        // The number of children
                        int chsz = branch.ChildCount;
                        // For each child, if it's a heap node, look up the child id and
                        // reference map in the sequence and set the reference accordingly,
                        for (int o = 0; o < chsz; ++o)
                        {
                            NodeId childId = branch.GetChild(o);
                            if (childId.IsInMemory)
                            {
                                // The ref is currently on the heap, so adjust accordingly
                                int refId = write.LookupRef(i, o);
                                branch.SetChild(refs[refId], o);
                            }
                        }

                        // Write out the branch to the store
                        long[] nodeData = branch.NodeData;
                        int    ndsz     = branch.NodeDataSize;

                        IAreaWriter writer = writers[i];
                        writer.WriteInt2(StoreBranchType);
                        writer.WriteInt2(1);                         // version
                        writer.WriteInt4(ndsz);
                        for (int o = 0; o < ndsz; ++o)
                        {
                            writer.WriteInt8(nodeData[o]);
                        }
                        writer.Finish();

                        // Make this into a branch node and add to the cache,
                        branch = new TreeBranch(refs[i], nodeData, ndsz);
                        // Put this branch in the cache,
                        lock (branchCache) {
                            branchCache.Set(refs[i], branch);
                        }
                    }
                    // Otherwise, it must be a leaf node,
                    else
                    {
                        TreeLeaf    leaf   = (TreeLeaf)node;
                        IAreaWriter writer = writers[i];
                        writer.WriteInt2(StoreLeafType);
                        writer.WriteInt2(1);                         // version
                        writer.WriteInt4(1);                         // reference count
                        writer.WriteInt4(leaf.Length);
                        leaf.WriteTo(writer);
                        writer.Finish();
                    }
                }

                return(refs);
            } finally {
                nodeStore.UnlockForWrite();
            }
        }
Example #4
0
        public long Create()
        {
            if (initialized)
            {
                throw new InvalidOperationException("This tree store is already initialized.");
            }

            // Temporary node heap for creating a starting database
            TreeNodeHeap nodeHeap = new TreeNodeHeap(17, 4 * 1024 * 1024);

            // Write a root node to the store,
            // Create an empty head node
            TreeLeaf headLeaf = nodeHeap.CreateLeaf(null, Key.Head, 256);

            // Insert a tree identification pattern
            headLeaf.Write(0, new byte[] { 1, 1, 1, 1 }, 0, 4);
            // Create an empty tail node
            TreeLeaf tailLeaf = nodeHeap.CreateLeaf(null, Key.Tail, 256);

            // Insert a tree identification pattern
            tailLeaf.Write(0, new byte[] { 1, 1, 1, 1 }, 0, 4);

            // The write sequence,
            TreeWrite seq = new TreeWrite();

            seq.NodeWrite(headLeaf);
            seq.NodeWrite(tailLeaf);
            IList <NodeId> refs = Persist(seq);

            // Create a branch,
            TreeBranch rootBranch = nodeHeap.CreateBranch(null, MaxBranchSize);

            rootBranch.Set(refs[0], 4, Key.Tail, refs[1], 4);

            seq = new TreeWrite();
            seq.NodeWrite(rootBranch);
            refs = Persist(seq);

            // The written root node reference,
            NodeId rootId = refs[0];

            // Delete the head and tail leaf, and the root branch
            nodeHeap.Delete(headLeaf.Id);
            nodeHeap.Delete(tailLeaf.Id);
            nodeHeap.Delete(rootBranch.Id);

            // Write this version info to the store,
            long versionId = WriteSingleVersionInfo(1, rootId, new List <NodeId>(0));

            // Make a first version
            VersionInfo versionInfo = new VersionInfo(1, rootId, versionId);

            versions.Add(versionInfo);

            // Flush this to the version list
            IAreaWriter versionList = nodeStore.CreateArea(64);

            versionList.WriteInt4(0x01433);
            versionList.WriteInt4(1);
            versionList.WriteInt8(versionId);
            versionList.Finish();

            // Get the versions id
            long versionListId = versionList.Id;

            // The final header
            IAreaWriter header = nodeStore.CreateArea(64);

            header.WriteInt4(0x09391);       // The magic value,
            header.WriteInt4(1);             // The version
            header.WriteInt8(versionListId);
            header.Finish();

            // Set up the internal variables,
            headerId = header.Id;

            initialized = true;
            // And return the header reference
            return(headerId);
        }
Example #5
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();
                    }
                }
            }
        }
Example #6
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);
            }
        }
Example #7
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);
            }
        }