// 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); } }
public HeapID ReplaceHeapItem(HeapID heapID, byte[] itemBytes) { return(m_heap.ReplaceHeapItem(heapID, itemBytes)); }