// We no longer create new TCs, we simply use the template and modify to another data tree
        public static TableContext CreateNewTableContext(PSTFile file, List <TableColumnDescriptor> columns)
        {
            HeapOnNode heap = HeapOnNode.CreateNewHeap(file);

            TableContextInfo tcInfo = new TableContextInfo();

            tcInfo.rgTCOLDESC = columns;
            tcInfo.UpdateDataLayout();

            HeapID newUserRoot = heap.AddItemToHeap(tcInfo.GetBytes());
            // The heap header may have just been updated
            HeapOnNodeHeader header = heap.HeapHeader;

            header.bClientSig  = OnHeapTypeName.bTypeTC;
            header.hidUserRoot = newUserRoot;
            heap.UpdateHeapHeader(header);

            BTreeOnHeapHeader bTreeHeader = new BTreeOnHeapHeader();

            bTreeHeader.cbKey = TableContextRowID.RecordKeyLength;
            bTreeHeader.cbEnt = TableContextRowID.RecordDataLength;

            tcInfo.hidRowIndex = heap.AddItemToHeap(bTreeHeader.GetBytes());
            // this will replace the item in place (as they have the same size since number of columns was not modified)
            heap.ReplaceHeapItem(header.hidUserRoot, tcInfo.GetBytes());

            return(new TableContext(heap, null));
        }
        /// <param name="subnodeBTree">Note: We use ref, this way we are able to create a new subnode BTree and update the subnodeBTree the caller provided</param>
        /// <param name="heapOrNodeID">Existing HeapOrNodeID</param>
        public static HeapOrNodeID StoreExternalProperty(PSTFile file, HeapOnNode heap, ref SubnodeBTree subnodeBTree, HeapOrNodeID heapOrNodeID, byte[] propertyBytes)
        {
            // We should avoid storing items with length of 0, because those are consideref freed, and could be repurposed
            if (propertyBytes.Length == 0)
            {
                RemoveExternalProperty(heap, subnodeBTree, heapOrNodeID);
                return(new HeapOrNodeID(HeapID.EmptyHeapID));
            }

            if (heapOrNodeID.IsHeapID) // if HeapOrNodeID is empty then IsHeapID == true
            {
                if (propertyBytes.Length <= HeapOnNode.MaximumAllocationLength)
                {
                    if (heapOrNodeID.IsEmpty)
                    {
                        return(new HeapOrNodeID(heap.AddItemToHeap(propertyBytes)));
                    }
                    else
                    {
                        return(new HeapOrNodeID(heap.ReplaceHeapItem(heapOrNodeID.HeapID, propertyBytes)));
                    }
                }
                else // old data (if exist) is stored on heap, but new data needs a subnode
                {
                    if (!heapOrNodeID.IsEmpty)
                    {
                        heap.RemoveItemFromHeap(heapOrNodeID.HeapID);
                    }

                    if (subnodeBTree == null)
                    {
                        subnodeBTree = new SubnodeBTree(file);
                    }
                    DataTree dataTree = new DataTree(file);
                    dataTree.AppendData(propertyBytes);
                    dataTree.SaveChanges();

                    NodeID subnodeID = file.Header.AllocateNextNodeID(NodeTypeName.NID_TYPE_LTP);
                    subnodeBTree.InsertSubnodeEntry(subnodeID, dataTree, null);

                    return(new HeapOrNodeID(subnodeID));
                }
            }
            else // old data is stored in a subnode
            {
                Subnode subnode = subnodeBTree.GetSubnode(heapOrNodeID.NodeID);
                if (subnode.DataTree != null)
                {
                    subnode.DataTree.Delete();
                }
                subnode.DataTree = new DataTree(subnodeBTree.File);
                subnode.DataTree.AppendData(propertyBytes);
                subnode.SaveChanges(subnodeBTree);
                return(new HeapOrNodeID(heapOrNodeID.NodeID));
            }
        }
        public void SetRowBytes(int rowIndex, byte[] rowBytes)
        {
            if (rowIndex >= RowCount)
            {
                throw new ArgumentException("Invalid rowIndex");
            }

            int rowLength = this.RowLength;

            if (m_tcInfo.hnidRows.IsHeapID)
            {
                // the RowMatrix is stored in the data tree
                byte[] rows      = m_heap.GetHeapItem(m_tcInfo.hnidRows.HeapID);
                int    rowOffset = (int)rowIndex * rowLength;
                Array.Copy(rowBytes, 0, rows, rowOffset, rowLength);

                HeapID oldHeapID = m_tcInfo.hnidRows.HeapID;
                // this will replace the item in place (as they have the same size)
                m_heap.ReplaceHeapItem(oldHeapID, rows);
            }
            else
            {
                // indicates that the item is stored in the subnode block, and the NID is the local NID under the subnode BTree
                NodeID rowsNodeID = m_tcInfo.hnidRows.NodeID;
                if (m_subnodeRows == null)
                {
                    m_subnodeRows = m_subnodeBTree.GetSubnode(rowsNodeID);
                }
                int       blockIndex      = (int)(rowIndex / m_rowsPerBlock);
                int       inBlockRowIndex = (int)(rowIndex % m_rowsPerBlock);
                DataBlock block           = m_subnodeRows.DataTree.GetDataBlock(blockIndex);
                int       offset          = inBlockRowIndex * rowLength;

                Array.Copy(rowBytes, 0, block.Data, offset, rowLength);
                m_subnodeRows.DataTree.UpdateDataBlock(blockIndex, block.Data);
            }
        }
Exemple #4
0
 public HeapID ReplaceHeapItem(HeapID heapID, byte[] itemBytes)
 {
     return(m_heap.ReplaceHeapItem(heapID, itemBytes));
 }