// handleWeightUpdate POST vertex/edge weight increment/decrement. POSTing to an uncreated // node or edge will create the node or edge (default 0 weight). Limit of 1000 vertices and 1000 edges. func (d *Data) handleWeightUpdate(ctx *datastore.VersionedCtx, db storage.GraphDB, w http.ResponseWriter, labelgraph *LabelGraph) error { // collect all vertices that need to be locked and wrap in transaction ("read only") open_vertices := d.extractOpenVertices(labelgraph) transaction_group, err := d.transaction_log.createTransactionGroup(open_vertices, true) if err != nil { transaction_group.closeTransaction() return fmt.Errorf("Could not create transaction group") } leftover := true // iterate until leftovers are empty for leftover { if len(transaction_group.lockedold_ids) == 0 { leftover = false } for i, vertex := range labelgraph.Vertices { // if it was already examined, continue if vertex.Id == 0 { continue } // if it the vertex was not locked, continue if _, ok := transaction_group.locked_ids[vertex.Id]; !ok { continue } // retrieve vertex, update or create depending on error status storedvert, err := db.GetVertex(ctx, vertex.Id) if err != nil { err = db.AddVertex(ctx, vertex.Id, vertex.Weight) if err != nil { transaction_group.closeTransaction() return fmt.Errorf("Failed to add vertex: %v\n", err) } } else { // increment/decrement weight err = db.SetVertexWeight(ctx, vertex.Id, storedvert.Weight+vertex.Weight) if err != nil { transaction_group.closeTransaction() return fmt.Errorf("Failed to add vertex: %v\n", err) } } // do not revisit labelgraph.Vertices[i].Id = 0 } for i, edge := range labelgraph.Edges { // if it was already examined, continue if edge.Id1 == 0 { continue } // if it the edge was not locked, continue if _, ok := transaction_group.locked_ids[edge.Id1]; !ok { continue } if _, ok := transaction_group.locked_ids[edge.Id2]; !ok { continue } // retrieve edge, update or create depending on error status storededge, err := db.GetEdge(ctx, edge.Id1, edge.Id2) if err != nil { err = db.AddEdge(ctx, edge.Id1, edge.Id2, edge.Weight) if err != nil { transaction_group.closeTransaction() return fmt.Errorf("Failed to add edge: %v\n", err) } } else { // increment/decrement weight err = db.SetEdgeWeight(ctx, edge.Id1, edge.Id2, storededge.Weight+edge.Weight) if err != nil { transaction_group.closeTransaction() return fmt.Errorf("Failed to update edge: %v\n", err) } } // do not revisit labelgraph.Edges[i].Id1 = 0 } if leftover { // wait on update to channel if there are leftovers transaction_group.waitForChange() // close transaction, create new transaction from leftovers in labelgraph transaction_group.closeTransaction() open_vertices = d.extractOpenVertices(labelgraph) transaction_group, _ = d.transaction_log.createTransactionGroup(open_vertices, true) } } transaction_group.closeTransaction() return nil }
// handleSubgraph loads, retrieves, or deletes a subgraph (more description in REST interface) func (d *Data) handleSubgraphBulk(ctx *datastore.VersionedCtx, db storage.GraphDB, w http.ResponseWriter, labelgraph *LabelGraph, method string) error { var err error if !d.setBusy() { return fmt.Errorf("Server busy with bulk transaction") } defer d.setNotBusy() // initial new graph labelgraph2 := new(LabelGraph) labelgraph2.Transactions = make([]transactionItem, 0) labelgraph2.Vertices = make([]labelVertex, 0) labelgraph2.Edges = make([]labelEdge, 0) // ?! do not grab edges that connect to outside vertices if method == "get" { var vertices []dvid.GraphVertex var edges []dvid.GraphEdge if len(labelgraph.Vertices) > 0 { used_vertices := make(map[dvid.VertexID]struct{}) for _, vertex := range labelgraph.Vertices { used_vertices[vertex.Id] = struct{}{} storedvert, err := db.GetVertex(ctx, vertex.Id) if err != nil { return fmt.Errorf("Failed to retrieve vertix %d: %v\n", vertex.Id, err) } vertices = append(vertices, storedvert) for _, vert2 := range storedvert.Vertices { if _, ok := used_vertices[vert2]; !ok { edge, err := db.GetEdge(ctx, storedvert.Id, vert2) if err != nil { return fmt.Errorf("Failed to retrieve edge %d-%d: %v\n", storedvert.Id, vert2, err) } edges = append(edges, edge) } } } } else { // if no set of vertices are supplied, just grab the whole graph vertices, err = db.GetVertices(ctx) if err != nil { return fmt.Errorf("Failed to retrieve vertices: %v\n", err) } edges, err = db.GetEdges(ctx) if err != nil { return fmt.Errorf("Failed to retrieve edges: %v\n", err) } } for _, vertex := range vertices { labelgraph2.Vertices = append(labelgraph2.Vertices, labelVertex{vertex.Id, vertex.Weight}) } for _, edge := range edges { labelgraph2.Edges = append(labelgraph2.Edges, labelEdge{edge.Vertexpair.Vertex1, edge.Vertexpair.Vertex2, edge.Weight}) } m, err := json.Marshal(labelgraph2) if err != nil { return fmt.Errorf("Could not serialize graph") } w.Header().Set("Content-Type", "application/json") fmt.Fprintf(w, string(m)) } else if method == "post" { // add list of vertices and edges from supplied JSON -- overwrite existing values for _, vertex := range labelgraph.Vertices { err := db.AddVertex(ctx, vertex.Id, vertex.Weight) if err != nil { return fmt.Errorf("Failed to add vertex: %v\n", err) } } for _, edge := range labelgraph.Edges { err := db.AddEdge(ctx, edge.Id1, edge.Id2, edge.Weight) if err != nil { return fmt.Errorf("Failed to add edge: %v\n", err) } } } else if method == "delete" { // delete the vertices supplied and all of their edges or delete the whole graph if len(labelgraph.Vertices) > 0 || len(labelgraph.Edges) > 0 { for _, vertex := range labelgraph.Vertices { db.RemoveVertex(ctx, vertex.Id) } for _, edge := range labelgraph.Edges { db.RemoveEdge(ctx, edge.Id1, edge.Id2) } } else { err = db.RemoveGraph(ctx) if err != nil { return fmt.Errorf("Failed to remove graph: %v\n", err) } } } else { err = fmt.Errorf("Does not support PUT") } return err }