// 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 }
// 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 }