Пример #1
0
// handleNeighbors returns the vertices and edges connected to the provided vertex
// (Should I protect this transaction like the update weight function?  It is probably
// unnecessary because any update based on retrieved information will be written to a
// property which has transactional protection)
func (d *Data) handleNeighbors(ctx *datastore.VersionedCtx, db storage.GraphDB, w http.ResponseWriter, path []string) error {
	labelgraph := new(LabelGraph)

	temp, err := strconv.Atoi(path[0])
	if err != nil {
		return fmt.Errorf("Vertex number not provided")
	}
	id := dvid.VertexID(temp)

	storedvert, err := db.GetVertex(ctx, id)
	if err != nil {
		return fmt.Errorf("Failed to retrieve vertix %d: %v\n", id, err)
	}

	labelgraph.Vertices = append(labelgraph.Vertices, labelVertex{storedvert.Id, storedvert.Weight})

	for _, vert2 := range storedvert.Vertices {
		vertex, err := db.GetVertex(ctx, vert2)
		if err != nil {
			return fmt.Errorf("Failed to retrieve vertex %d: %v\n", vertex.Id, err)
		}
		labelgraph.Vertices = append(labelgraph.Vertices, labelVertex{vertex.Id, vertex.Weight})
		edge, err := db.GetEdge(ctx, id, vert2)
		if err != nil {
			return fmt.Errorf("Failed to retrieve edge %d-%d: %v\n", vertex.Id, vert2, err)
		}
		labelgraph.Edges = append(labelgraph.Edges, labelEdge{edge.Vertexpair.Vertex1, edge.Vertexpair.Vertex2, edge.Weight})
	}
	m, err := json.Marshal(labelgraph)
	if err != nil {
		return fmt.Errorf("Could not serialize graph")
	}
	w.Header().Set("Content-Type", "application/json")
	fmt.Fprintf(w, string(m))
	return nil
}
Пример #2
0
// handleMerge merges a list of vertices onto the final vertex in the Vertices list
func (d *Data) handleMerge(ctx *datastore.VersionedCtx, db storage.GraphDB, w http.ResponseWriter, labelgraph *LabelGraph) error {

	numverts := len(labelgraph.Vertices)
	if numverts < 2 {
		return fmt.Errorf("Must specify at least two vertices for merging")
	}

	overlapweights := make(map[dvid.VertexID]float64)
	vertweight := float64(0)
	var keepvertex dvid.GraphVertex
	allverts := make(map[dvid.VertexID]struct{})
	keepverts := make(map[dvid.VertexID]struct{})

	// accumulate weights, find common edges
	for i, vertex := range labelgraph.Vertices {
		vert, err := db.GetVertex(ctx, vertex.Id)
		if err != nil {
			return fmt.Errorf("Failed to retrieve vertex %d: %v\n", vertex.Id, err)
		}
		allverts[vert.Id] = struct{}{}
		vertweight += vert.Weight

		if i == (numverts - 1) {
			keepvertex = vert
		} else {
			for _, vert2 := range vert.Vertices {
				edge, err := db.GetEdge(ctx, vert.Id, vert2)
				if err != nil {
					return fmt.Errorf("Failed to retrieve edge %d-%d: %v\n", vertex.Id, vert2, err)
				}
				overlapweights[vert2] += edge.Weight
			}
		}
	}

	// examine keep vertex (save edges so only the weights are updated)
	for _, vert2 := range keepvertex.Vertices {
		edge, err := db.GetEdge(ctx, keepvertex.Id, vert2)
		if err != nil {
			return fmt.Errorf("Failed to retrieve edge %d-%d: %v\n", keepvertex.Id, vert2, err)
		}
		overlapweights[vert2] += edge.Weight
		keepverts[vert2] = struct{}{}
	}

	// use specified weights even if marked as 0
	for _, edge := range labelgraph.Edges {
		id := edge.Id1
		baseid := edge.Id2
		if keepvertex.Id == edge.Id1 {
			id = edge.Id2
			baseid = edge.Id1
		}
		if baseid == keepvertex.Id {
			if _, ok := overlapweights[id]; ok {
				overlapweights[id] = edge.Weight
			}
		}
	}

	// if user specifies an edge weight other than 0 (?! -- somehow allow in future)
	// use that weight
	if labelgraph.Vertices[numverts-1].Weight != 0 {
		vertweight = labelgraph.Vertices[numverts-1].Weight
	}

	for id2, newweight := range overlapweights {
		if _, ok := allverts[id2]; !ok {
			// only examine edges where the node is not internal
			if _, ok := keepverts[id2]; !ok {
				// if not in keepverts create new edge
				err := db.AddEdge(ctx, keepvertex.Id, id2, newweight)
				if err != nil {
					return fmt.Errorf("Failed to create edge %d-%d: %v\n", keepvertex.Id, id2, err)
				}
			} else {
				// else just update weight
				err := db.SetEdgeWeight(ctx, keepvertex.Id, id2, newweight)
				if err != nil {
					return fmt.Errorf("Failed to update weight on edge %d-%d: %v\n", keepvertex.Id, id2, err)
				}
			}
		}
	}

	// update vertex weight
	err := db.SetVertexWeight(ctx, labelgraph.Vertices[numverts-1].Id, vertweight)
	if err != nil {
		return fmt.Errorf("Failed to update weight on vertex %d: %v\n", keepvertex.Id, err)
	}

	// remove old vertices which will remove the old edges
	for i, vertex := range labelgraph.Vertices {
		if i == (numverts - 1) {
			break
		}
		err := db.RemoveVertex(ctx, vertex.Id)
		if err != nil {
			return fmt.Errorf("Failed to remove vertex %d: %v\n", vertex.Id, err)
		}
	}
	return nil
}
Пример #3
0
// 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
}
Пример #4
0
// 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
}
Пример #5
0
// handleProperty retrieves or deletes properties that can be added to a vertex or edge -- data posted
// or retrieved uses default compression
func (d *Data) handleProperty(ctx *datastore.VersionedCtx, db storage.GraphDB, w http.ResponseWriter, r *http.Request, path []string, method string) error {

	edgemode := false
	var propertyname string

	if len(path) == 3 {
		edgemode = true
		propertyname = path[2]
	} else if len(path) != 2 {
		return fmt.Errorf("Incorrect number of parameters specified for handling properties")
	} else {
		propertyname = path[1]
	}
	temp, err := strconv.Atoi(path[0])
	if err != nil {
		return fmt.Errorf("Vertex number not provided")
	}
	id1 := dvid.VertexID(temp)

	id2 := dvid.VertexID(0)
	if edgemode {
		temp, err := strconv.Atoi(path[1])
		if err != nil {
			return fmt.Errorf("Vertex number not provided")
		}
		id2 = dvid.VertexID(temp)
	}

	// remove a property from a vertex or edge
	if method == "delete" {
		if edgemode {
			db.RemoveEdgeProperty(ctx, id1, id2, propertyname)
			if err != nil {
				return fmt.Errorf("Failed to remove edge property %d-%d %s: %v\n", id1, id2, propertyname, err)
			}
		} else {
			db.RemoveVertexProperty(ctx, id1, propertyname)
			if err != nil {
				return fmt.Errorf("Failed to remove vertex property %d %s: %v\n", id1, propertyname, err)
			}
		}
	} else if method == "get" {
		var data []byte
		if edgemode {
			data, err = db.GetEdgeProperty(ctx, id1, id2, propertyname)
		} else {
			data, err = db.GetVertexProperty(ctx, id1, propertyname)
		}
		if err != nil {
			return fmt.Errorf("Failed to get property %s: %v\n", propertyname, err)
		}
		uncompress := true
		value, _, e := dvid.DeserializeData(data, uncompress)
		if e != nil {
			err = fmt.Errorf("Unable to deserialize data for property '%s': %v\n", propertyname, e.Error())
			return err
		}

		w.Header().Set("Content-Type", "application/octet-stream")
		_, err = w.Write(value)
		if err != nil {
			return err
		}
	} else if method == "post" {
		// read as binary and load into propertyname
		data, err := ioutil.ReadAll(r.Body)
		if err != nil {
			return err
		}
		serialization, err := dvid.SerializeData(data, d.Compression(), d.Checksum())
		if err != nil {
			return fmt.Errorf("Unable to serialize data: %v\n", err)
		}
		if edgemode {
			err = db.SetEdgeProperty(ctx, id1, id2, propertyname, serialization)
		} else {
			err = db.SetVertexProperty(ctx, id1, propertyname, serialization)
		}
		if err != nil {
			return fmt.Errorf("Failed to add property %s: %v\n", propertyname, err)
		}
	}

	return err
}
Пример #6
0
// handelPropertyTransaction allows gets/posts (really puts) of edge or vertex properties.
func (d *Data) handlePropertyTransaction(ctx *datastore.VersionedCtx, db storage.GraphDB, w http.ResponseWriter, r *http.Request, path []string, method string) error {
	if len(path) < 2 {
		return fmt.Errorf("Must specify edges or vertices in URI and property name")
	}
	if method == "delete" {
		return fmt.Errorf("Transactional delete not supported")
	}

	edgemode := false
	if path[0] == "edges" {
		edgemode = true
	} else if path[0] != "vertices" {
		return fmt.Errorf("Must specify edges or vertices in URI")
	}
	propertyname := path[1]

	readonly := false
	if method == "get" {
		readonly = true
	}
	data, err := ioutil.ReadAll(r.Body)

	// only allow 1000 vertices to be locked
	transactions, start, err := d.transaction_log.createTransactionGroupBinary(data, readonly)
	defer transactions.closeTransaction()
	if err != nil {
		return fmt.Errorf("Failed to create property transaction: %v", err)
	}

	returned_data := transactions.exportTransactionsBinary()

	if method == "post" {
		// deserialize transaction (vertex or edge) -- use URI?
		num_properties := binary.LittleEndian.Uint64(data[start:])
		start += 8

		for i := uint64(0); i < num_properties; i++ {
			temp := binary.LittleEndian.Uint64(data[start:])
			id := dvid.VertexID(temp)
			var id2 dvid.VertexID
			start += 8
			if edgemode {
				temp = binary.LittleEndian.Uint64(data[start:])
				id2 = dvid.VertexID(temp)
				start += 8
			}
			data_size := binary.LittleEndian.Uint64(data[start:])
			start += 8
			data_begin := start

			start += int(data_size)
			data_end := start

			if data_begin == data_end {
				continue
			}

			// check if post is possible
			if _, ok := transactions.locked_ids[id]; !ok {
				continue
			}
			if edgemode {
				if _, ok := transactions.locked_ids[id2]; !ok {
					continue
				}
			}

			// execute post
			serialization, err := dvid.SerializeData(data[data_begin:data_end], d.Compression(), d.Checksum())
			if err != nil {
				return fmt.Errorf("Unable to serialize data: %v\n", err)
			}
			if edgemode {
				err = db.SetEdgeProperty(ctx, id, id2, propertyname, serialization)
			} else {
				err = db.SetVertexProperty(ctx, id, propertyname, serialization)
			}
			if err != nil {
				return fmt.Errorf("Failed to add property %s: %v\n", propertyname, err)
			}
		}
	} else {
		num_properties := binary.LittleEndian.Uint64(data[start:])
		start += 8
		num_properties_loc := len(returned_data)
		longbuf := make([]byte, 8, 8)
		binary.LittleEndian.PutUint64(longbuf, 0)
		returned_data = append(returned_data, longbuf...)
		num_executed_transactions := uint64(0)

		// read the vertex or edge properties desired
		for i := uint64(0); i < num_properties; i++ {
			temp := binary.LittleEndian.Uint64(data[start:])
			id := dvid.VertexID(temp)
			var id2 dvid.VertexID
			start += 8
			if edgemode {
				temp := binary.LittleEndian.Uint64(data[start:])
				id2 = dvid.VertexID(temp)
				start += 8
			}

			// check if post is possible
			if _, ok := transactions.locked_ids[id]; !ok {
				continue
			}
			if edgemode {
				if _, ok := transactions.locked_ids[id2]; !ok {
					continue
				}
			}

			// execute get command
			var dataout []byte
			if edgemode {
				dataout, err = db.GetEdgeProperty(ctx, id, id2, propertyname)
			} else {
				dataout, err = db.GetVertexProperty(ctx, id, propertyname)
			}

			// serialize return data only if there is return data and no error;
			// otherwise return just return the id and size of 0
			var data_serialized []byte
			if (err == nil) && len(dataout) > 0 {
				uncompress := true
				data_serialized, _, err = dvid.DeserializeData(dataout, uncompress)
				if err != nil {
					return fmt.Errorf("Unable to deserialize data for property '%s': %v\n", propertyname, err)
				}
			}

			// save transaction
			num_executed_transactions += 1
			binary.LittleEndian.PutUint64(longbuf, uint64(id))
			returned_data = append(returned_data, longbuf...)
			if edgemode {
				binary.LittleEndian.PutUint64(longbuf, uint64(id2))
				returned_data = append(returned_data, longbuf...)
			}
			binary.LittleEndian.PutUint64(longbuf, uint64(len(data_serialized)))
			returned_data = append(returned_data, longbuf...)
			returned_data = append(returned_data, data_serialized...)
		}

		// update the number of transactions
		binary.LittleEndian.PutUint64(returned_data[num_properties_loc:], num_executed_transactions)
	}

	w.Header().Set("Content-Type", "application/octet-stream")
	_, err = w.Write(returned_data)
	return err
}