From 8a3f587b049f0a25d0a2c83e07c5bebd4f1206d0 Mon Sep 17 00:00:00 2001 From: Jordan Liggitt Date: Mon, 10 Feb 2020 13:24:27 -0500 Subject: [PATCH] Add fast path to node authorizer for node/edge removal --- plugin/pkg/auth/authorizer/node/graph.go | 56 +++++++++++++++--------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/plugin/pkg/auth/authorizer/node/graph.go b/plugin/pkg/auth/authorizer/node/graph.go index 630dd3302c3..e0076feca65 100644 --- a/plugin/pkg/auth/authorizer/node/graph.go +++ b/plugin/pkg/auth/authorizer/node/graph.go @@ -175,7 +175,7 @@ func (g *Graph) deleteVertex_locked(vertexType vertexType, namespace, name strin // find existing neighbors with a single edge (meaning we are their only neighbor) neighborsToRemove := []graph.Node{} - neighborsToRecompute := []graph.Node{} + edgesToRemoveFromIndexes := []graph.Edge{} g.graph.VisitFrom(vertex, func(neighbor graph.Node) bool { // this downstream neighbor has only one edge (which must be from us), so remove them as well if g.graph.Degree(neighbor) == 1 { @@ -188,8 +188,8 @@ func (g *Graph) deleteVertex_locked(vertexType vertexType, namespace, name strin // this upstream neighbor has only one edge (which must be to us), so remove them as well neighborsToRemove = append(neighborsToRemove, neighbor) } else { - // recompute the destination edge index on this neighbor - neighborsToRecompute = append(neighborsToRecompute, neighbor) + // decrement the destination edge index on this neighbor if the edge between us was a destination edge + edgesToRemoveFromIndexes = append(edgesToRemoveFromIndexes, g.graph.EdgeBetween(vertex, neighbor)) } return true }) @@ -202,9 +202,9 @@ func (g *Graph) deleteVertex_locked(vertexType vertexType, namespace, name strin g.removeVertex_locked(neighbor.(*namedVertex)) } - // recompute destination indexes for neighbors that dropped outbound edges - for _, neighbor := range neighborsToRecompute { - g.recomputeDestinationIndex_locked(neighbor) + // remove edges from destination indexes for neighbors that dropped outbound edges + for _, edge := range edgesToRemoveFromIndexes { + g.removeEdgeFromDestinationIndex_locked(edge) } } @@ -220,19 +220,17 @@ func (g *Graph) deleteEdges_locked(fromType, toType vertexType, toNamespace, toN // delete all edges between vertices of fromType and toVert neighborsToRemove := []*namedVertex{} - neighborsToRecompute := []*namedVertex{} + edgesToRemove := []graph.Edge{} g.graph.VisitTo(toVert, func(from graph.Node) bool { fromVert := from.(*namedVertex) if fromVert.vertexType != fromType { return true } - // remove the edge - g.graph.RemoveEdge(simple.Edge{F: fromVert, T: toVert}) - // track vertexes that changed edges - if g.graph.Degree(fromVert) == 0 { + // this neighbor has only one edge (which must be to us), so remove them as well + if g.graph.Degree(fromVert) == 1 { neighborsToRemove = append(neighborsToRemove, fromVert) } else { - neighborsToRecompute = append(neighborsToRecompute, fromVert) + edgesToRemove = append(edgesToRemove, g.graph.EdgeBetween(from, toVert)) } return true }) @@ -242,9 +240,30 @@ func (g *Graph) deleteEdges_locked(fromType, toType vertexType, toNamespace, toN g.removeVertex_locked(v) } - // recompute destination indexes for neighbors that dropped outbound edges - for _, v := range neighborsToRecompute { - g.recomputeDestinationIndex_locked(v) + // remove edges and decrement destination indexes for neighbors that dropped outbound edges + for _, edge := range edgesToRemove { + g.graph.RemoveEdge(edge) + g.removeEdgeFromDestinationIndex_locked(edge) + } +} + +// A fastpath for recomputeDestinationIndex_locked for "removing edge" case. +func (g *Graph) removeEdgeFromDestinationIndex_locked(e graph.Edge) { + n := e.From() + // don't maintain indices for nodes with few edges + edgeCount := g.graph.Degree(n) + if edgeCount < g.destinationEdgeThreshold { + delete(g.destinationEdgeIndex, n.ID()) + return + } + + // decrement the nodeID->destinationID refcount in the index, if the index exists + index := g.destinationEdgeIndex[n.ID()] + if index == nil { + return + } + if destinationEdge, ok := e.(*destinationEdge); ok { + index.decrement(destinationEdge.DestinationID()) } } @@ -300,12 +319,7 @@ func (g *Graph) recomputeDestinationIndex_locked(n graph.Node) { } return true }) - - if len(index.members) < g.destinationEdgeThreshold { - delete(g.destinationEdgeIndex, n.ID()) - } else { - g.destinationEdgeIndex[n.ID()] = index - } + g.destinationEdgeIndex[n.ID()] = index } // AddPod should only be called once spec.NodeName is populated.