Example #1
0
        public TreeBranch(NodeId nodeId, long[] data, int dataSize)
        {
            if (nodeId.IsInMemory)
                throw new ArgumentException("Only store nodes permitted.");

            this.nodeId = nodeId;

            children = data;
            childrenCount = (dataSize + 2)/5;
        }
 public TreeSystemTransaction(ITreeSystem treeStore, long versionId, NodeId rootNodeId, bool readOnly)
 {
     this.treeStore = treeStore;
     this.rootNodeId = rootNodeId;
     this.versionId = versionId;
     updateVersion = 0;
     nodeDeletes = null;
     nodeInserts = null;
     this.readOnly = readOnly;
     disposed = false;
 }
Example #3
0
        public TreeBranch(NodeId nodeId, int maxChildrenCount)
        {
            if (!nodeId.IsInMemory)
                throw new ArgumentException("Only heap node permitted.");
            if ((maxChildrenCount%2) != 0)
                throw new ArgumentException("max_children_count must be a multiple of 2.");
            if (maxChildrenCount > 65530)
                throw new ArgumentException("Branch children count is limited to 65530");
            if (maxChildrenCount < 6)
                // While I did test with 4, tree balancing is rather tough at 4 so we
                // should have this at at least 6.
                throw new ArgumentException("max_children_count must be >= 6");

            this.nodeId = nodeId;

            children = new long[(maxChildrenCount*5) - 2];
            childrenCount = 0;
        }
        internal void FlushNodesToStore(NodeId[] nodeIds)
        {
            // If not disposed,
            if (!disposed) {

                // Compact the entire tree
                object[] mergeBuffer = new object[5];
                CompactNode(Key.Head, RootNodeId, mergeBuffer, Key.Head, Key.Tail);

                // Flush the reference node list,
                RootNodeId = (FlushNodes(RootNodeId, nodeIds));

                // Update the version so any data file objects will flush with the
                // changes.
                ++updateVersion;

                // Check out the changes
                treeStore.CheckPoint();
            }
        }
 internal bool IsHeapNode(NodeId nodeId)
 {
     return nodeId.IsInMemory;
 }
        private int PopulateSequence(NodeId id, TreeWrite sequence)
        {
            // If it's not a heap node, return
            if (!IsHeapNode(id))
                return -1;

            // It is a heap node, so fetch
            ITreeNode node = FetchNode(id);
            // Is it a leaf or a branch?
            if (node is TreeLeaf)
                // If it's a leaf, simply write it out
                return sequence.NodeWrite(node);

            if (node is TreeBranch) {
                // This is a branch,
                // Sequence this branch to be written out,
                int branchId = sequence.NodeWrite(node);
                // For each child in the branch,
                TreeBranch branch = (TreeBranch) node;
                int sz = branch.ChildCount;
                for (int i = 0; i < sz; ++i) {
                    NodeId child = branch.GetChild(i);
                    // Sequence the child
                    int childId = PopulateSequence(child, sequence);
                    // If something could be sequenced in the child,
                    if (childId != -1) {
                        // Make the branch command,
                        sequence.BranchLink(branchId, i, childId);
                    }
                }
                // Return the id of the branch in the sequence,
                return branchId;
            } else {
                throw new ApplicationException("Unknown node type.");
            }
        }
Example #7
0
 public AreaTreeLeaf(NodeId nodeId, int leafSize, IArea area)
 {
     this.nodeId   = nodeId;
     this.leafSize = leafSize;
     this.area     = area;
 }
Example #8
0
 internal void SetChild(NodeId childPointer, int n)
 {
     CheckReadOnly();
     SetChildOverride(childPointer, n);
 }
        private void LogStoreChange(byte type, NodeId pointer)
        {
            if (!treeStore.NotifyNodeChanged)
                return;

            // Special node type changes are not logged
            if (pointer.IsSpecial)
                return;

            if (type == 0) {
                // This type is for deleted nodes,
                NodeDeletes.Add(pointer);
            } else if (type == 1) {
                // This type is for inserts,
                NodeInserts.Add(pointer);
            } else {
                throw new ApplicationException("Incorrect type");
            }
        }
Example #10
0
        public TreeReportNode CreateDiagnosticGraph()
        {
            CheckErrorState();

            // Create the header node
            TreeReportNode headerNode = new TreeReportNode("header", headerId);

            // Get the header area
            IArea headerArea = nodeStore.GetArea(headerId);

            headerArea.Position = 8;
            // Read the versions list,
            long versionListRef = headerArea.ReadInt8();

            // Create the version node
            TreeReportNode versionsNode =
                new TreeReportNode("versions list", versionListRef);

            // Set this as a child to the header
            headerNode.ChildNodes.Add(versionsNode);

            // Read the versions list area
            // magic(int), versions count(int), list of version id objects.
            IArea versionsArea = nodeStore.GetArea(versionListRef);

            if (versionsArea.ReadInt4() != 0x01433)
            {
                throw new IOException("Incorrect magic value 0x01433");
            }

            int versCount = versionsArea.ReadInt4();

            // For each id from the versions area, read in the associated VersionInfo
            // object into the 'vers' array.
            for (int i = 0; i < versCount; ++i)
            {
                long vInfoRef = versionsArea.ReadInt8();
                // Set up the information in our node
                TreeReportNode vInfoNode = new TreeReportNode("version", vInfoRef);

                // Read in the version information node
                IArea  vInfoArea  = nodeStore.GetArea(vInfoRef);
                int    magic      = vInfoArea.ReadInt4();
                int    ver        = vInfoArea.ReadInt4();
                long   versionId  = vInfoArea.ReadInt8();
                long   rnrHigh    = vInfoArea.ReadInt8();
                long   rnrLow     = vInfoArea.ReadInt8();
                NodeId rootNodeId = new NodeId(rnrHigh, rnrLow);

                vInfoNode.SetProperty("MAGIC", magic);
                vInfoNode.SetProperty("VER", ver);
                vInfoNode.SetProperty("version_id", versionId);
                // Make the deleted area list into a property
                int deletedAreaCount = vInfoArea.ReadInt4();
                if (deletedAreaCount > 0)
                {
                    for (int n = 0; n < deletedAreaCount; ++n)
                    {
                        long   delnHigh  = vInfoArea.ReadInt8();
                        long   delnLow   = vInfoArea.ReadInt8();
                        NodeId delNodeId = new NodeId(delnHigh, delnLow);
                        vInfoNode.ChildNodes.Add(new TreeReportNode("delete", delNodeId));
                    }
                }

                // Add the child node (the root node of the version graph).
                vInfoNode.ChildNodes.Add(CreateDiagnosticRootGraph(Key.Head, rootNodeId));

                // Add this to the version list node
                versionsNode.ChildNodes.Add(vInfoNode);
            }

            // Return the header node
            return(headerNode);
        }
        private Object[] DeleteFromLeaf(long leftOffset, NodeId leaf, long startPos, long endPos, Key inLeftKey)
        {
            Debug.Assert(startPos < endPos);

            TreeLeaf treeLeaf = (TreeLeaf) UnfreezeNode(FetchNode(leaf));
            const int leafStart = 0;
            int leafEnd = treeLeaf.Length;
            int delStart = (int) Math.Max(startPos - leftOffset, (long) leafStart);
            int delEnd = (int) Math.Min(endPos - leftOffset, (long) leafEnd);

            int removeAmount = delEnd - delStart;

            // Remove from the end point,
            treeLeaf.Shift(delEnd, -removeAmount);

            return new object[] {
                                    treeLeaf.Id,
                                    (long) removeAmount,
                                    inLeftKey, false
                                };
        }
Example #12
0
        private ITreeNode FetchNode(NodeId nodeId)
        {
            // Is it a special static node?
            if (nodeId.IsSpecial)
            {
                return(SpecialStaticNode(nodeId));
            }

            // Is this a branch node in the cache?
            NodeId     cacheKey = nodeId;
            TreeBranch branch;

            lock (branchCache) {
                branch = (TreeBranch)branchCache.Get(cacheKey);
                if (branch != null)
                {
                    return(branch);
                }
            }

            // Not found in the cache, so fetch the area from the backing store and
            // create the node type.

            // Get the area for the node
            IArea nodeArea = nodeStore.GetArea(ToInt64StoreAddress(nodeId));
            // Wrap around a buffered BinaryRader for reading values from the store.
            BinaryReader input = new BinaryReader(new AreaInputStream(nodeArea, 256));

            short nodeType = input.ReadInt16();

            // Is the node type a leaf node?
            if (nodeType == StoreLeafType)
            {
                // Read the key
                input.ReadInt16();                 // version
                input.ReadInt32();                 // reference count
                int leafSize = input.ReadInt32();

                // Return a leaf that's mapped to the data in the store
                nodeArea.Position = 0;
                return(new AreaTreeLeaf(nodeId, leafSize, nodeArea));
            }
            // Is the node type a branch node?
            if (nodeType == StoreBranchType)
            {
                // Note that the entire branch is loaded into memory now,
                input.ReadInt16();                 // version
                int    childDataSize = input.ReadInt32();
                long[] dataArr       = new long[childDataSize];
                for (int i = 0; i < childDataSize; ++i)
                {
                    dataArr[i] = input.ReadInt64();
                }
                branch = new TreeBranch(nodeId, dataArr, childDataSize);
                // Put this branch in the cache,
                lock (branchCache) {
                    branchCache.Set(cacheKey, branch);
                    // And return the branch
                    return(branch);
                }
            }

            throw new ApplicationException("Unknown node type: " + nodeType);
        }
Example #13
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 #14
0
 internal static ITreeNode SpecialStaticNode(NodeId nodeId)
 {
     return(nodeId.CreateSpecialTreeNode());
 }
Example #15
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 #16
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 #17
0
 public TreeBranch(NodeId nodeId, TreeBranch branch, int maxChildrenCount)
     : this(nodeId, maxChildrenCount)
 {
     Array.Copy(branch.children, 0, children, 0, Math.Min(branch.children.Length, children.Length));
     childrenCount = branch.ChildCount;
 }
Example #18
0
        private TreeReportNode CreateDiagnosticRootGraph(Key leftKey, NodeId id)
        {
            // The node being returned
            TreeReportNode node;

            // Open the area
            IArea area = nodeStore.GetArea(ToInt64StoreAddress(id));
            // What type of node is this?
            short nodeType = area.ReadInt2();
            // The version
            short ver = area.ReadInt2();

            if (nodeType == StoreLeafType)
            {
                // Read the reference count,
                long refCount = area.ReadInt4();
                // The number of bytes in the leaf
                int leafSize = area.ReadInt4();

                // Set up the leaf node object
                node = new TreeReportNode("leaf", id);
                node.SetProperty("VER", ver);
                node.SetProperty("key", leftKey.ToString());
                node.SetProperty("reference_count", refCount);
                node.SetProperty("leaf_size", leafSize);
            }
            else if (nodeType == StoreBranchType)
            {
                // The data size area containing the children information
                int    childDataSize = area.ReadInt4();
                long[] dataArr       = new long[childDataSize];
                for (int i = 0; i < childDataSize; ++i)
                {
                    dataArr[i] = area.ReadInt8();
                }
                // Create the TreeBranch object to query it
                TreeBranch branch = new TreeBranch(id, dataArr, childDataSize);
                // Set up the branch node object
                node = new TreeReportNode("branch", id);
                node.SetProperty("VER", ver);
                node.SetProperty("key", leftKey.ToString());
                node.SetProperty("branch_size", branch.ChildCount);
                // Recursively add each child into the tree
                for (int i = 0; i < branch.ChildCount; ++i)
                {
                    NodeId childId = branch.GetChild(i);
                    // If the id is a special node, skip it
                    if (childId.IsSpecial)
                    {
                        // Should we record special nodes?
                    }
                    else
                    {
                        Key            newLeftKey = (i > 0) ? branch.GetKey(i) : leftKey;
                        TreeReportNode bn         = new TreeReportNode("child_meta", id);
                        bn.SetProperty("extent", branch.GetChildLeafElementCount(i));
                        node.ChildNodes.Add(bn);
                        node.ChildNodes.Add(CreateDiagnosticRootGraph(newLeftKey, childId));
                    }
                }
            }
            else
            {
                throw new IOException("Unknown node type: " + nodeType);
            }

            return(node);
        }
        private void CompactNode(Key farLeft, NodeId id, object[] mergeBuffer, Key minBound, Key maxBound)
        {
            // If the ref is not on the heap, return the ref,
            if (!IsHeapNode(id))
                return;

            // Fetch the node,
            ITreeNode node = FetchNode(id);
            // If the node is a leaf, return the ref,
            if (node is TreeLeaf)
                return;

            // If the node is a branch,
            if (node is TreeBranch) {
                // Cast to a branch
                TreeBranch branch = (TreeBranch) node;

                // We ask the node for the child sub-tree that will contain the range
                // of this key
                int firstChildI = branch.SearchFirst(minBound);
                int lastChildI = branch.SearchLast(maxBound);

                // first_child_i may be negative which means a key reference is equal
                // to the key being searched, in which case we follow the left branch.
                if (firstChildI < 0) {
                    firstChildI = -(firstChildI + 1);
                }

                // Compact the children,
                for (int x = firstChildI; x <= lastChildI; ++x) {
                    // Change far left to represent the new far left node
                    Key newFarLeft = (x > 0) ? branch.GetKey(x) : farLeft;

                    // We don't change max_bound because it's not necessary.
                    CompactNode(newFarLeft, branch.GetChild(x), mergeBuffer, minBound, maxBound);
                }

                // The number of children in this branch,
                int sz = branch.ChildCount;

                // Now try and merge the compacted children,
                int i = firstChildI;
                // We must not let there be less than 3 children
                while (sz > 3 && i <= lastChildI - 1) {
                    // The left and right children nodes,
                    NodeId leftChildId = branch.GetChild(i);
                    NodeId rightChildId = branch.GetChild(i + 1);
                    // If at least one of them is a heap node we attempt to merge the
                    // nodes,
                    if (IsHeapNode(leftChildId) || IsHeapNode(rightChildId)) {
                        // Set the left left key and right left key of the references,
                        Key leftLeftKey = (i > 0) ? branch.GetKey(i) : farLeft;
                        Key rightLeftKey = branch.GetKey(i + 1);
                        // Attempt to merge the nodes,
                        int nodeResult = MergeNodes(branch.GetKey(i + 1),
                                                     leftChildId, rightChildId,
                                                     leftLeftKey, rightLeftKey,
                                                     mergeBuffer);
                        // If we merged into a single node then we update the left and
                        // delete the right
                        if (nodeResult == 1) {
                            branch.SetChild((NodeId) mergeBuffer[0], i);
                            branch.SetChildLeafElementCount((long) mergeBuffer[1], i);
                            branch.RemoveChild(i + 1);
                            // Reduce the size but don't increase i, because we may want to
                            // merge again.
                            --sz;
                            --lastChildI;
                        } else if (nodeResult == 2) {
                            // Two result but there was a change (the left was increased in
                            // size)
                            branch.SetChild((NodeId) mergeBuffer[0], i);
                            branch.SetChildLeafElementCount((long) mergeBuffer[1], i);
                            branch.SetKeyToLeft((Key) mergeBuffer[2], i + 1);
                            branch.SetChild((NodeId) mergeBuffer[3], i + 1);
                            branch.SetChildLeafElementCount((long) mergeBuffer[4], i + 1);
                            ++i;
                        } else {
                            // Otherwise, no change so skip to the next child,
                            ++i;
                        }
                    }
                        // left or right are not nodes on the heap so go to next,
                    else {
                        ++i;
                    }
                }
            }
        }
Example #20
0
 private long ToInt64StoreAddress(NodeId nodeId)
 {
     return(nodeId.Low);
 }
        private ITreeNode FetchNodeIfLocallyAvailable(NodeId nodeId)
        {
            // If it's a heap node,
            if (IsHeapNode(nodeId)) {
                return FetchNode(nodeId);
            }

            // If the node is locally available, return it,
            if (treeStore.IsNodeAvailable(nodeId)) {
                return treeStore.FetchNodes(new NodeId[] {nodeId})[0];
            }
            // Otherwise return null
            return null;
        }
Example #22
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 #23
0
 public SparseLeafNode(NodeId nodeId, byte sparseByte, int leafSize)
 {
     this.nodeId = nodeId;
     this.leafSize = leafSize;
     this.sparseByte = sparseByte;
 }
        private Object[] RecurseRemoveBranches(long leftOffset, int height, NodeId node, long startPos, long endPos, Key inLeftKey)
        {
            // Do we know if this is a leaf node?
            if (treeHeight == height)
                return DeleteFromLeaf(leftOffset, node, startPos, endPos, inLeftKey);

            // Fetch the node,
            ITreeNode treeNode = FetchNode(node);
            if (treeNode is TreeLeaf) {
                // Leaf reach, so set the tree height and return
                treeHeight = height;
                return DeleteFromLeaf(leftOffset, node, startPos, endPos, inLeftKey);
            }

            // The amount removed,
            long removeCount = 0;

            // This is a branch,
            TreeBranch treeBranch = (TreeBranch) treeNode;
            treeBranch = (TreeBranch) UnfreezeNode(treeBranch);

            Key parentLeftKey = inLeftKey;

            // Find all the children branches between the bounds,
            int childCount = treeBranch.ChildCount;
            long pos = leftOffset;
            for (int i = 0; i < childCount && pos < endPos; ++i) {
                long childNodeSize = treeBranch.GetChildLeafElementCount(i);
                long nextPos = pos + childNodeSize;

                // Test if start_pos/end_pos bounds intersects with this child,
                if (startPos < nextPos && endPos > pos) {
                    // Yes, we intersect,

                    // Make sure the branch is on the heap,
                    NodeId childNode = treeBranch.GetChild(i);

                    // If we intersect entirely remove the child from the branch,
                    if (pos >= startPos && nextPos <= endPos) {
                        // Delete the child tree,
                        DeleteChildTree(height + 1, childNode);
                        removeCount += childNodeSize;

                        // If removing the first child, bubble up a new left_key
                        if (i == 0) {
                            parentLeftKey = treeBranch.GetKey(1);
                        }
                            // Otherwise parent left key doesn't change
                        else {
                            parentLeftKey = inLeftKey;
                        }

                        // Remove the child from the branch,
                        treeBranch.RemoveChild(i);
                        --i;
                        --childCount;
                    } else {
                        // We don't intersect entirely, so recurse on this,
                        // The left key
                        Key rLeftKey = (i == 0) ? inLeftKey : treeBranch.GetKey(i);

                        object[] rv = RecurseRemoveBranches(pos, height + 1, childNode, startPos, endPos, rLeftKey);
                        NodeId newChildRef = (NodeId) rv[0];
                        long removedInChild = (long) rv[1];
                        Key childLeftKey = (Key) rv[2];

                        removeCount += removedInChild;

                        // Update the child,
                        treeBranch.SetChild(newChildRef, i);
                        treeBranch.SetChildLeafElementCount(childNodeSize - removedInChild, i);
                        if (i == 0) {
                            parentLeftKey = childLeftKey;
                        } else {
                            treeBranch.SetKeyToLeft(childLeftKey, i);
                            parentLeftKey = inLeftKey;
                        }
                    }
                }

                // Next child in the branch,
                pos = nextPos;
            }

            // Return the reference and remove count,
            bool parentRebalance = (treeBranch.ChildCount <= 2);
            return new Object[] {
                                    treeBranch.Id, removeCount,
                                    parentLeftKey, parentRebalance
                                };
        }
        private int MergeNodes(Key middleKeyValue, NodeId leftId, NodeId rightId, Key leftLeftKey, Key rightLeftKey, object[] mergeBuffer)
        {
            // Fetch the nodes,
            ITreeNode leftNode = FetchNode(leftId);
            ITreeNode rightNode = FetchNode(rightId);
            // Are we merging branches or leafs?
            if (leftNode is TreeLeaf) {
                TreeLeaf lleaf = (TreeLeaf) leftNode;
                TreeLeaf rleaf = (TreeLeaf) rightNode;
                // Check the keys are identical,
                if (leftLeftKey.Equals(rightLeftKey)) {
                    // 80% capacity on a leaf
                    int capacity80 = (int) (0.80*MaxLeafByteSize);
                    // True if it's possible to full merge left and right into a single
                    bool fullyMerge = lleaf.Length + rleaf.Length <= MaxLeafByteSize;
                    // Only proceed if the leafs can be fully merged or the left is less
                    // than 80% full,
                    if (fullyMerge || lleaf.Length < capacity80) {
                        // Move elements from the right leaf to the left leaf so that either
                        // the right node becomes completely empty or if that's not possible
                        // the left node is 80% full.
                        if (fullyMerge) {
                            // We can fit both nodes into a single node so merge into a single
                            // node,
                            TreeLeaf nleaf = (TreeLeaf) UnfreezeNode(lleaf);
                            byte[] copyBuf = new byte[rleaf.Length];
                            rleaf.Read(0, copyBuf, 0, copyBuf.Length);
                            nleaf.Write(nleaf.Length, copyBuf, 0, copyBuf.Length);

                            // Delete the right node,
                            DeleteNode(rleaf.Id);

                            // Setup the merge state
                            mergeBuffer[0] = nleaf.Id;
                            mergeBuffer[1] = (long) nleaf.Length;
                            return 1;
                        }

                        // Otherwise, we move bytes from the right leaf into the left
                        // leaf until it is 80% full,
                        int toCopy = capacity80 - lleaf.Length;
                        // Make sure we are copying at least 4 bytes and there are enough
                        // bytes available in the right leaf to make the copy,
                        if (toCopy > 4 && rleaf.Length > toCopy) {
                            // Unfreeze both the nodes,
                            TreeLeaf mlleaf = (TreeLeaf) UnfreezeNode(lleaf);
                            TreeLeaf mrleaf = (TreeLeaf) UnfreezeNode(rleaf);
                            // Copy,
                            byte[] copyBuf = new byte[toCopy];
                            mrleaf.Read(0, copyBuf, 0, toCopy);
                            mlleaf.Write(mlleaf.Length, copyBuf, 0, toCopy);
                            // Shift the data in the right leaf,
                            mrleaf.Shift(toCopy, -toCopy);

                            // Return the merge state
                            mergeBuffer[0] = mlleaf.Id;
                            mergeBuffer[1] = (long) mlleaf.Length;
                            mergeBuffer[2] = rightLeftKey;
                            mergeBuffer[3] = mrleaf.Id;
                            mergeBuffer[4] = (long) mrleaf.Length;
                            return 2;
                        }
                    }
                } // leaf keys unequal
            } else if (leftNode is TreeBranch) {
                // Merge branches,
                TreeBranch lbranch = (TreeBranch) leftNode;
                TreeBranch rbranch = (TreeBranch) rightNode;

                int capacity75 = (int) (0.75*MaxBranchSize);
                // True if it's possible to full merge left and right into a single
                bool fullyMerge = lbranch.ChildCount + rbranch.ChildCount <= MaxBranchSize;

                // Only proceed if left is less than 75% full,
                if (fullyMerge || lbranch.ChildCount < capacity75) {
                    // Move elements from the right branch to the left leaf only if the
                    // branches can be completely merged into a node
                    if (fullyMerge) {
                        // We can fit both nodes into a single node so merge into a single
                        // node,
                        TreeBranch nbranch = (TreeBranch) UnfreezeNode(lbranch);
                        // Merge,
                        nbranch.MergeLeft(rbranch, middleKeyValue, rbranch.ChildCount);

                        // Delete the right branch,
                        DeleteNode(rbranch.Id);

                        // Setup the merge state
                        mergeBuffer[0] = nbranch.Id;
                        mergeBuffer[1] = nbranch.LeafElementCount;
                        return 1;
                    }

                    // Otherwise, we move children from the right branch into the left
                    // branch until it is 75% full,
                    int toCopy = capacity75 - lbranch.ChildCount;
                    // Make sure we are copying at least 4 bytes and there are enough
                    // bytes available in the right leaf to make the copy,
                    if (toCopy > 2 && rbranch.ChildCount > toCopy + 3) {
                        // Unfreeze the nodes,
                        TreeBranch mlbranch = (TreeBranch) UnfreezeNode(lbranch);
                        TreeBranch mrbranch = (TreeBranch) UnfreezeNode(rbranch);
                        // And merge
                        Key newMiddleValue = mlbranch.MergeLeft(mrbranch, middleKeyValue, toCopy);

                        // Setup and return the merge state
                        mergeBuffer[0] = mlbranch.Id;
                        mergeBuffer[1] = mlbranch.LeafElementCount;
                        mergeBuffer[2] = newMiddleValue;
                        mergeBuffer[3] = mrbranch.Id;
                        mergeBuffer[4] = mrbranch.LeafElementCount;
                        return 2;
                    }
                }
            } else {
                throw new ApplicationException("Unknown node type.");
            }

            // Signifies no change to the branch,
            return 3;
        }
        internal void DeleteNode(NodeId nodeId)
        {
            // If we are deleting a node that's on the temporary node heap, we delete
            // it immediately.  We know such nodes are only accessed within the scope of
            // this transaction so we can free up the resources immediately.

            // Is this a heap node?
            if (IsHeapNode(nodeId)) {
                // Delete it now
                NodeHeap.Delete(nodeId);
            } else {
                // Not a heap node, so we log that this node needs to be deleted when
                // we are certain it has gone out of scope of any concurrent transaction
                // that may need access to this data.
                // Logs a delete operation,
                LogStoreChange((byte)0, nodeId);
            }
        }
        private TreeBranch RecurseRebalanceTree(long leftOffset, int height, NodeId nodeId, long absolutePosition, Key inLeftKey)
        {
            // Put the node in memory,
            TreeBranch branch = (TreeBranch) FetchNode(nodeId);

            int sz = branch.ChildCount;
            int i;
            long pos = leftOffset;
            // Find the first child i that contains the position.
            for (i = 0; i < sz; ++i) {
                long childElemCount = branch.GetChildLeafElementCount(i);
                // abs position falls within bounds,
                if (absolutePosition >= pos &&
                    absolutePosition < pos + childElemCount) {
                    break;
                }
                pos += childElemCount;
            }

            if (i > 0) {
                NodeId leftId = branch.GetChild(i - 1);
                NodeId rightId = branch.GetChild(i);

                // Only continue if both left and right are on the heap
                if (IsHeapNode(leftId) &&
                    IsHeapNode(rightId) &&
                    IsHeapNode(nodeId)) {

                    Key leftKey = (i - 1 == 0)
                                   	? inLeftKey
                                   	: branch.GetKey(i - 1);
                    Key rightKey = branch.GetKey(i);

                    // Perform the merge operation,
                    Key midKeyValue = rightKey;
                    object[] mergeBuffer = new Object[5];
                    int merge_result = MergeNodes(midKeyValue, leftId, rightId,
                                                  leftKey, rightKey, mergeBuffer);
                    if (merge_result == 1) {
                        branch.SetChild((NodeId) mergeBuffer[0], i - 1);
                        branch.SetChildLeafElementCount((long) mergeBuffer[1], i - 1);
                        branch.RemoveChild(i);
                    }
                        //
                    else if (merge_result == 2) {
                        branch.SetChild((NodeId) mergeBuffer[0], i - 1);
                        branch.SetChildLeafElementCount((long) mergeBuffer[1], i - 1);
                        branch.SetKeyToLeft((Key) mergeBuffer[2], i);
                        branch.SetChild((NodeId) mergeBuffer[3], i);
                        branch.SetChildLeafElementCount((long) mergeBuffer[4], i);
                    }
                }
            }

            // After merge, we don't know how the children will be placed, so we
            // do another search on the child to descend to,

            sz = branch.ChildCount;
            pos = leftOffset;
            // Find the first child i that contains the position.
            for (i = 0; i < sz; ++i) {
                long childElemCount = branch.GetChildLeafElementCount(i);
                // abs position falls within bounds,
                if (absolutePosition >= pos &&
                    absolutePosition < pos + childElemCount) {
                    break;
                }
                pos += childElemCount;
            }

            // Descend on 'i'
            ITreeNode descendChild = FetchNode(branch.GetChild(i));

            // Finish if we hit a leaf
            if (descendChild is TreeLeaf) {
                // End if we hit the leaf,
                return branch;
            }

            Key newLeftKey = (i == 0)
                               	? inLeftKey
                               	: branch.GetKey(i);

            // Otherwise recurse on the child,
            TreeBranch child_branch =
                RecurseRebalanceTree(pos, height + 1,
                                     descendChild.Id, absolutePosition,
                                     newLeftKey);

            // Make sure we unfreeze the branch
            branch = (TreeBranch) UnfreezeNode(branch);

            // Update the child,
            branch.SetChild(child_branch.Id, i);
            branch.SetChildLeafElementCount(child_branch.LeafElementCount, i);

            // And return this branch,
            return branch;
        }
Example #28
0
 public VersionInfo(long versionId, NodeId rootNodePointer, long versionInfoRef)
 {
     this.versionId       = versionId;
     this.rootNodePointer = rootNodePointer;
     this.versionInfoRef  = versionInfoRef;
 }
 private void WrittenNode(ITreeNode node, NodeId nodeId)
 {
     // Delete the reference to the old node,
     DeleteNode(node.Id);
     // Log the insert operation.
     LogStoreChange((byte) 1, nodeId);
 }
Example #30
0
 private NodeId WriteNode(NodeId nodeId)
 {
     return ts.WriteNode(nodeId);
 }
        internal ITreeNode FetchNode(NodeId nodeId)
        {
            // Is it a node we can fetch from the local node heap?
            if (IsHeapNode(nodeId)) {
                ITreeNode n = NodeHeap.FetchNode(nodeId);
                if (n == null)
                    throw new NullReferenceException(nodeId.ToString());
                return n;
            }

            // If there's nothing in the prefetch keymap,
            if (prefetchKeymap.Count == 0) {
                ITreeNode n = treeStore.FetchNodes(new NodeId[] {nodeId})[0];
                if (n == null)
                    throw new NullReferenceException(nodeId.ToString());
                return n;
            }

            List<NodeId> prefetchNodeset = new List<NodeId>();
            prefetchNodeset.Add(nodeId);
            DiscoverPrefetchNodeSet(prefetchNodeset);

            int len = prefetchNodeset.Count;
            NodeId[] nodeRefs = new NodeId[len];
            for (int i = 0; i < len; ++i) {
                nodeRefs[i] = prefetchNodeset[i];
            }

            {
                // Otherwise fetch the node from the tree store
                ITreeNode n = treeStore.FetchNodes(nodeRefs)[0];
                if (n == null)
                    throw new NullReferenceException(nodeId.ToString());
                return n;
            }
        }
Example #32
0
 public PlaceholderLeaf(TreeSystemTransaction ts, NodeId nodeId, int size)
 {
     this.ts = ts;
     this.nodeId = nodeId;
     this.size = size;
 }
 internal bool IsFrozen(NodeId nodeId)
 {
     return !nodeId.IsInMemory;
     //    // A node is frozen if either it is in the store (nodeId >= 0) or it has
     //    // the lock bit set to 0
     //    return nodeId >= 0 ||
     //           (nodeId & 0x02000000000000000L) == 0;
 }
Example #34
0
 private void DeleteNode(NodeId nodeId)
 {
     ts.DeleteNode(nodeId);
 }
        internal NodeId WriteNode(NodeId nodeId)
        {
            // Create the sequence,
            TreeWrite sequence = new TreeWrite();
            // Create the command sequence to write this tree out,
            int rootId = PopulateSequence(nodeId, sequence);

            if (rootId != -1) {
                // Write out this sequence,
                IList<NodeId> refs = treeStore.Persist(sequence);

                // Update internal structure for each node written,
                IList<ITreeNode> nodes = sequence.BranchNodes;
                int sz = nodes.Count;
                for (int i = 0; i < sz; ++i) {
                    WrittenNode(nodes[i], refs[i]);
                }
                int bnodesSz = sz;
                nodes = sequence.LeafNodes;
                sz = nodes.Count;
                for (int i = 0; i < sz; ++i) {
                    WrittenNode(nodes[i], refs[i + bnodesSz]);
                }

                // Normalize the pointer,
                if (rootId >= TreeWrite.BranchPoint) {
                    rootId = rootId - TreeWrite.BranchPoint;
                } else {
                    rootId = rootId + bnodesSz;
                }

                // Return a reference to the node written,
                return refs[rootId];
            }
            return nodeId;
        }
Example #36
0
 private ITreeNode FetchNode(NodeId nodeId)
 {
     return ts.FetchNode(nodeId);
 }
 private void ActualDisposeNode(NodeId nodeId)
 {
     // Dispose of the node,
     treeStore.DisposeNode(nodeId);
     // And return
 }
Example #38
0
 private bool IsFrozen(NodeId nodeId)
 {
     return ts.IsFrozen(nodeId);
 }
        private void DeleteChildTree(int height, NodeId node)
        {
            if (height == treeHeight) {
                // This is a known leaf node,
                DeleteNode(node);
                return;
            }

            // Fetch the node,
            ITreeNode treeNode = FetchNode(node);
            if (treeNode is TreeLeaf) {
                // Leaf reached, so set the tree height, delete and return
                treeHeight = height;
                DeleteNode(node);
                return;
            }

            // The behaviour here changes depending on the system implementation.
            // Either we can simply unlink from the entire tree or we need to
            // recursely free all the leaf nodes.
            if (treeStore.NotifyNodeChanged) {
                // Need to account for all nodes so delete the node and all in the
                // sub-tree.
                DisposeTree(node);
            } else {
                // Otherwise we can simply unlink the branches on the heap and be
                // done with it.
                DisposeHeapNodes(node);
            }
        }
Example #40
0
 private bool IsHeapNode(NodeId nodeId)
 {
     return ts.IsHeapNode(nodeId);
 }
        private void DisposeTree(NodeId id)
        {
            // It is a heap node, so fetch
            ITreeNode node = FetchNode(id);
            // Is it a leaf or a branch?
            if (node is TreeLeaf) {
                // If it's a leaf, dispose it
                DeleteNode(id);
                // And return,
                return;
            }

            if (node is TreeBranch) {
                // This is a branch, so we need to dipose the children if they are heap
                TreeBranch branch = (TreeBranch) node;

                int sz = branch.ChildCount;
                for (int i = 0; i < sz; ++i) {
                    // Recurse for each child,
                    DisposeTree(branch.GetChild(i));
                }
                // Then dispose this,
                DeleteNode(id);
                // And return,
                return;
            }

            throw new ApplicationException("Unknown node type.");
        }
Example #42
0
        private void StackPush(int childIndex, long offset, NodeId nodeId)
        {
            if (stackSize + StackFrameSize >= stack.Length) {
                // Expand the size of the stack.
                // The default size should be plenty for most iterators unless we
                // happen to be iterating across a particularly deep B+Tree.
                long[] newStack = new long[stack.Length*2];
                Array.Copy(stack, 0, newStack, 0, stack.Length);
                stack = newStack;
            }

            stack[stackSize] = childIndex;
            stack[stackSize + 1] = offset;
            stack[stackSize + 2] = nodeId.High;
            stack[stackSize + 3] = nodeId.Low;
            stackSize += StackFrameSize;
        }
        private NodeId FlushNodes(NodeId id, NodeId[] includeIds)
        {
            if (!IsHeapNode(id))
                return id;

            // Is this reference in the list?
            int c = Array.BinarySearch(includeIds, id);
            if (c < 0) {
                // It was not found, so go to the children,
                // Note that this node will change if it's a branch node, but the
                // reference to it will not change.

                // It is a heap node, so fetch
                ITreeNode node = FetchNode(id);
                // Is it a leaf or a branch?
                if (node is TreeLeaf)
                    return id;

                if (node is TreeBranch) {
                    // This is a branch, so we need to write out any children that are on
                    // the heap before we write out the branch itself,
                    TreeBranch branch = (TreeBranch) node;

                    int sz = branch.ChildCount;

                    for (int i = 0; i < sz; ++i) {
                        NodeId oldId = branch.GetChild(i);
                        // Recurse
                        NodeId newId = FlushNodes(oldId, includeIds);
                        branch.SetChild(newId, i);
                    }
                    // And return the reference
                    return id;
                }

                throw new ApplicationException("Unknown node type.");
            }

            // This node was in the 'includeIds' list so write it out now,
            return WriteNode(id);
        }
Example #44
0
 public void SetChildOverride(NodeId childPointer, int n)
 {
     children[(n * 5) + 0] = childPointer.High;
     children[(n * 5) + 1] = childPointer.Low;
 }