private void SealNodeForBulkIncomingEdgeAddition(NodeId target) { BufferPointer <NodeEdgeListHeader> targetInEdges = InEdges.GetBufferPointer(target.Value); targetInEdges.Buffer[targetInEdges.Index].Seal(); Contract.Assert(targetInEdges.Buffer[targetInEdges.Index].IsSealed, "Node should be sealed"); }
private void AddEdges(NodeId target, HashSet <Edge> incomingEdges) { BufferPointer <NodeEdgeListHeader> targetInEdges = InEdges.GetBufferPointer(target.Value); Contract.Assert(targetInEdges.Buffer[targetInEdges.Index].IsSealed, "Bulk additions can only be made to sealed nodes"); using (m_globalLock.AcquireReadLock()) { Contract.Assert(m_state == MutableGraphState.Mutating, "Graph mutations are not permitted after sealing"); foreach (var incoming in incomingEdges) { var source = incoming.OtherNode; var incomingLock = m_locks[GetLockNumber(source.Value)]; using (AcquireLockForState(incomingLock, MutableGraphState.Mutating)) { // AddEdgeUnchecked is thread-safe with respect to concurrent modifications AddEdgeUnchecked( source: source, target: target, targetInEdges: targetInEdges, isLight: incoming.IsLight, bulkAddingTargetIncoming: true); } } Interlocked.Increment(ref m_modificationsSinceLastNodeHeightComputation); } }
private bool AddEdgeUnchecked(NodeId source, NodeId target, bool isLight) { BufferPointer <NodeEdgeListHeader> targetInEdges = InEdges.GetBufferPointer(target.Value); Contract.Assert(!targetInEdges.Buffer[targetInEdges.Index].IsSealed, "Attempted to add edge to sealed node"); return(AddEdgeUnchecked( source: source, target: target, targetInEdges: targetInEdges, isLight: isLight, bulkAddingTargetIncoming: false)); }
private bool IsSealed(NodeId target) { BufferPointer <NodeEdgeListHeader> targetInEdges = InEdges.GetBufferPointer(target.Value); return(targetInEdges.Buffer[targetInEdges.Index].IsSealed); }
/// <summary> /// Loads this graph from a given binary stream. /// </summary> private void Load(BuildXLReader reader) { m_lastNodeId = (int)reader.ReadUInt32(); m_edgeCount = reader.ReadInt32(); Contract.Assume(m_lastNodeId <= NodeId.MaxValue); // Create buffer with space for in edges and out edges m_edgeBuffer.Initialize(m_edgeCount * 2); int edgeIndex = 0; // Read the out edges { var accessor = m_edgeBuffer.GetAccessor(); // TODO: This loop takes 70% of the deserialization time; make faster. for (uint i = 1; i <= m_lastNodeId; ++i) { int outNodeCount = reader.ReadInt32Compact(); int startEdgeIndex = edgeIndex; for (int j = 0; j < outNodeCount; ++j) { var outgoingEdge = Edge.Deserialize(reader); accessor[edgeIndex] = outgoingEdge; edgeIndex++; } OutEdges[i] = new NodeEdgeListHeader(startEdgeIndex, outNodeCount); } } // Read the count of in edges // TODO: This loop takes 10% of the deserialization time; make faster. for (uint i = 1; i <= m_lastNodeId; i++) { int nodeHeight = reader.ReadInt32Compact(); NodeHeights[i] = nodeHeight; int inEdgeCount = reader.ReadInt32Compact(); // first edge index starts at end of edge span for this node and is decrements as edges // are discovered and added below. At the end the first edge index will // be at the beginning of the span edgeIndex += inEdgeCount; InEdges[i] = new NodeEdgeListHeader(edgeIndex, inEdgeCount); } // Write each out edge set to graph and compute the in edges // TODO: This parallel loop takes 20% of the (sequential) deserialization time; make faster. Parallel.For(1, m_lastNodeId + 1, (i) => { NodeId node = new NodeId((uint)i); var accessor = m_edgeBuffer.GetAccessor(); foreach (var e in GetOutgoingEdges(node)) { var inEdge = new Edge(node, e.IsLight); // Note: We access the InEdges array element directly, not via the ConcurrentDenseIndex's indexer property. // As a result, we mutate the actual array element, instead of a copy. var p = InEdges.GetBufferPointer(e.OtherNode.Value); var index = p.Buffer[p.Index].InterlockedDecrementFirstIndex(); // Set the prior index and point header at that index. The initial value // to index should be set to the index after the span. So this will always // set an index within the edge span accessor[index] = inEdge; } }); }