diff --git a/client/go/main.go b/client/go/main.go index e671f2822afb6d3260d5ffe7d843c656b2a3f9e8..3912bb9dcf94ba4c6d3bcc7a3622c59273b061f4 100644 --- a/client/go/main.go +++ b/client/go/main.go @@ -23,13 +23,13 @@ import ( "golang.org/x/net/context" "google.golang.org/grpc" - "github.com/dgraph-io/dgraph/query/pb" + "github.com/dgraph-io/dgraph/query/graph" "github.com/dgraph-io/dgraph/x" ) var glog = x.Log("client") var ip = flag.String("ip", "127.0.0.1:8081", "Port to communicate with server") -var query = flag.String("query", "", "Query sent to the server") +var q = flag.String("query", "", "Query sent to the server") func main() { flag.Parse() @@ -40,9 +40,9 @@ func main() { } defer conn.Close() - c := pb.NewDGraphClient(conn) + c := graph.NewDGraphClient(conn) - r, err := c.Query(context.Background(), &pb.GraphRequest{Query: *query}) + r, err := c.Query(context.Background(), &graph.Request{Query: *q}) if err != nil { x.Err(glog, err).Fatal("Error in getting response from server") } diff --git a/query/graph/graphresponse.pb.go b/query/graph/graphresponse.pb.go new file mode 100644 index 0000000000000000000000000000000000000000..fefbbb2bb5a008e850922ce5325b4eeeb58062cf --- /dev/null +++ b/query/graph/graphresponse.pb.go @@ -0,0 +1,177 @@ +// Code generated by protoc-gen-go. +// source: graphresponse.proto +// DO NOT EDIT! + +/* +Package graph is a generated protocol buffer package. + +It is generated from these files: + graphresponse.proto + +It has these top-level messages: + Request + Value + Node +*/ +package graph + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +import ( + context "golang.org/x/net/context" + grpc "google.golang.org/grpc" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +const _ = proto.ProtoPackageIsVersion1 + +type Request struct { + Query string `protobuf:"bytes,1,opt,name=query" json:"query,omitempty"` +} + +func (m *Request) Reset() { *m = Request{} } +func (m *Request) String() string { return proto.CompactTextString(m) } +func (*Request) ProtoMessage() {} +func (*Request) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } + +type Value struct { + Str string `protobuf:"bytes,1,opt,name=str" json:"str,omitempty"` +} + +func (m *Value) Reset() { *m = Value{} } +func (m *Value) String() string { return proto.CompactTextString(m) } +func (*Value) ProtoMessage() {} +func (*Value) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } + +type Node struct { + Uid uint64 `protobuf:"varint,1,opt,name=uid" json:"uid,omitempty"` + Xid string `protobuf:"bytes,2,opt,name=xid" json:"xid,omitempty"` + Attribute string `protobuf:"bytes,3,opt,name=attribute" json:"attribute,omitempty"` + Properties map[string]*Value `protobuf:"bytes,4,rep,name=properties" json:"properties,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + Children []*Node `protobuf:"bytes,5,rep,name=children" json:"children,omitempty"` +} + +func (m *Node) Reset() { *m = Node{} } +func (m *Node) String() string { return proto.CompactTextString(m) } +func (*Node) ProtoMessage() {} +func (*Node) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } + +func (m *Node) GetProperties() map[string]*Value { + if m != nil { + return m.Properties + } + return nil +} + +func (m *Node) GetChildren() []*Node { + if m != nil { + return m.Children + } + return nil +} + +func init() { + proto.RegisterType((*Request)(nil), "graph.Request") + proto.RegisterType((*Value)(nil), "graph.Value") + proto.RegisterType((*Node)(nil), "graph.Node") +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion2 + +// Client API for DGraph service + +type DGraphClient interface { + Query(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Node, error) +} + +type dGraphClient struct { + cc *grpc.ClientConn +} + +func NewDGraphClient(cc *grpc.ClientConn) DGraphClient { + return &dGraphClient{cc} +} + +func (c *dGraphClient) Query(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Node, error) { + out := new(Node) + err := grpc.Invoke(ctx, "/graph.DGraph/Query", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// Server API for DGraph service + +type DGraphServer interface { + Query(context.Context, *Request) (*Node, error) +} + +func RegisterDGraphServer(s *grpc.Server, srv DGraphServer) { + s.RegisterService(&_DGraph_serviceDesc, srv) +} + +func _DGraph_Query_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Request) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DGraphServer).Query(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/graph.DGraph/Query", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DGraphServer).Query(ctx, req.(*Request)) + } + return interceptor(ctx, in, info, handler) +} + +var _DGraph_serviceDesc = grpc.ServiceDesc{ + ServiceName: "graph.DGraph", + HandlerType: (*DGraphServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Query", + Handler: _DGraph_Query_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, +} + +var fileDescriptor0 = []byte{ + // 268 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x5c, 0x90, 0x41, 0x4f, 0x83, 0x40, + 0x10, 0x85, 0xa5, 0xb0, 0xd5, 0x0e, 0x46, 0xcd, 0xea, 0x01, 0xab, 0x89, 0xcd, 0x1e, 0xb4, 0x27, + 0x62, 0xf0, 0x62, 0xf4, 0xaa, 0xf1, 0x60, 0x62, 0x74, 0x0f, 0xde, 0xa9, 0x4c, 0x2c, 0xb1, 0x01, + 0xdc, 0x5d, 0x8c, 0xfd, 0xed, 0x5e, 0x64, 0x06, 0x44, 0xd2, 0xdb, 0xe3, 0x7d, 0xb3, 0xc3, 0x9b, + 0x07, 0x87, 0xef, 0x26, 0xad, 0x96, 0x06, 0x6d, 0x55, 0x16, 0x16, 0xe3, 0xca, 0x94, 0xae, 0x94, + 0x82, 0x4d, 0x75, 0x06, 0xdb, 0x1a, 0x3f, 0x6b, 0xb4, 0x4e, 0x1e, 0x81, 0x68, 0x84, 0x59, 0x47, + 0xde, 0xcc, 0x9b, 0x4f, 0x74, 0xfb, 0xa1, 0x8e, 0x41, 0xbc, 0xa6, 0xab, 0x1a, 0xe5, 0x01, 0xf8, + 0xd6, 0x99, 0x0e, 0x92, 0x54, 0x3f, 0x1e, 0x04, 0x4f, 0x65, 0xc6, 0xa8, 0xce, 0x33, 0x46, 0x81, + 0x26, 0x49, 0xce, 0x77, 0xe3, 0x8c, 0xda, 0xe1, 0x46, 0xca, 0x53, 0x98, 0xa4, 0xce, 0x99, 0x7c, + 0x51, 0x3b, 0x8c, 0x7c, 0xf6, 0xff, 0x0d, 0x79, 0x0b, 0xd0, 0xc4, 0xaa, 0xd0, 0xb8, 0x1c, 0x6d, + 0x14, 0xcc, 0xfc, 0x79, 0x98, 0x9c, 0xc4, 0x1c, 0x31, 0xa6, 0x5f, 0xc4, 0xcf, 0x3d, 0xbd, 0x2f, + 0x9c, 0x59, 0xeb, 0xc1, 0xb8, 0xbc, 0x80, 0x9d, 0xb7, 0x65, 0xbe, 0xca, 0x0c, 0x16, 0x91, 0xe0, + 0xa7, 0xe1, 0xe0, 0xa9, 0xee, 0xe1, 0xf4, 0x11, 0xf6, 0x37, 0xf6, 0x50, 0xd0, 0x0f, 0xfc, 0x3b, + 0x99, 0xa4, 0x54, 0x20, 0xbe, 0xe8, 0x60, 0x0e, 0x1f, 0x26, 0xbb, 0xdd, 0x2a, 0x2e, 0x41, 0xb7, + 0xe8, 0x66, 0x74, 0xed, 0x25, 0x97, 0x30, 0xbe, 0x7b, 0x20, 0x24, 0xcf, 0x41, 0xbc, 0x50, 0x57, + 0x72, 0xaf, 0x9b, 0xed, 0x1a, 0x9d, 0x0e, 0x63, 0xa8, 0xad, 0xc5, 0x98, 0x9b, 0xbf, 0xfa, 0x0d, + 0x00, 0x00, 0xff, 0xff, 0xe1, 0x8a, 0xe7, 0x89, 0x90, 0x01, 0x00, 0x00, +} diff --git a/query/graph/graphresponse.proto b/query/graph/graphresponse.proto new file mode 100644 index 0000000000000000000000000000000000000000..81545972f2a51f0f440d2746e5b544411ab79890 --- /dev/null +++ b/query/graph/graphresponse.proto @@ -0,0 +1,25 @@ +// To compile this file run the command below from inside the graph directory +// protoc --go_out=plugins=grpc:. *.proto + +syntax="proto3"; +package graph; + +service DGraph { + rpc Query (Request) returns (Node) {} +} + +message Request { + string query = 1; +} + +message Value { + string str = 1; +} + +message Node { + uint64 uid = 1; + string xid = 2; + string attribute = 3; + map<string, Value> properties = 4; + repeated Node children = 5; // Each node can have multiple children +} diff --git a/query/pb/graphresponse.pb.go b/query/pb/graphresponse.pb.go deleted file mode 100644 index 55014d70b55686d2340fbe30697e096461799fbf..0000000000000000000000000000000000000000 --- a/query/pb/graphresponse.pb.go +++ /dev/null @@ -1,193 +0,0 @@ -// Code generated by protoc-gen-go. -// source: graphresponse.proto -// DO NOT EDIT! - -/* -Package pb is a generated protocol buffer package. - -It is generated from these files: - graphresponse.proto - -It has these top-level messages: - UidList - Result - GraphRequest - GraphResponse -*/ -package pb - -import proto "github.com/golang/protobuf/proto" -import fmt "fmt" -import math "math" - -import ( - context "golang.org/x/net/context" - grpc "google.golang.org/grpc" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -const _ = proto.ProtoPackageIsVersion1 - -type UidList struct { - Uids []uint64 `protobuf:"varint,1,rep,name=uids" json:"uids,omitempty"` -} - -func (m *UidList) Reset() { *m = UidList{} } -func (m *UidList) String() string { return proto.CompactTextString(m) } -func (*UidList) ProtoMessage() {} -func (*UidList) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } - -type Result struct { - Values [][]byte `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty"` - Uidmatrix []*UidList `protobuf:"bytes,2,rep,name=uidmatrix" json:"uidmatrix,omitempty"` -} - -func (m *Result) Reset() { *m = Result{} } -func (m *Result) String() string { return proto.CompactTextString(m) } -func (*Result) ProtoMessage() {} -func (*Result) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } - -func (m *Result) GetUidmatrix() []*UidList { - if m != nil { - return m.Uidmatrix - } - return nil -} - -type GraphRequest struct { - Query string `protobuf:"bytes,1,opt,name=query" json:"query,omitempty"` -} - -func (m *GraphRequest) Reset() { *m = GraphRequest{} } -func (m *GraphRequest) String() string { return proto.CompactTextString(m) } -func (*GraphRequest) ProtoMessage() {} -func (*GraphRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } - -type GraphResponse struct { - Attribute string `protobuf:"bytes,1,opt,name=attribute" json:"attribute,omitempty"` - Result *Result `protobuf:"bytes,2,opt,name=result" json:"result,omitempty"` - Children []*GraphResponse `protobuf:"bytes,3,rep,name=children" json:"children,omitempty"` -} - -func (m *GraphResponse) Reset() { *m = GraphResponse{} } -func (m *GraphResponse) String() string { return proto.CompactTextString(m) } -func (*GraphResponse) ProtoMessage() {} -func (*GraphResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } - -func (m *GraphResponse) GetResult() *Result { - if m != nil { - return m.Result - } - return nil -} - -func (m *GraphResponse) GetChildren() []*GraphResponse { - if m != nil { - return m.Children - } - return nil -} - -func init() { - proto.RegisterType((*UidList)(nil), "pb.UidList") - proto.RegisterType((*Result)(nil), "pb.Result") - proto.RegisterType((*GraphRequest)(nil), "pb.GraphRequest") - proto.RegisterType((*GraphResponse)(nil), "pb.GraphResponse") -} - -// Reference imports to suppress errors if they are not otherwise used. -var _ context.Context -var _ grpc.ClientConn - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion2 - -// Client API for DGraph service - -type DGraphClient interface { - Query(ctx context.Context, in *GraphRequest, opts ...grpc.CallOption) (*GraphResponse, error) -} - -type dGraphClient struct { - cc *grpc.ClientConn -} - -func NewDGraphClient(cc *grpc.ClientConn) DGraphClient { - return &dGraphClient{cc} -} - -func (c *dGraphClient) Query(ctx context.Context, in *GraphRequest, opts ...grpc.CallOption) (*GraphResponse, error) { - out := new(GraphResponse) - err := grpc.Invoke(ctx, "/pb.DGraph/Query", in, out, c.cc, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -// Server API for DGraph service - -type DGraphServer interface { - Query(context.Context, *GraphRequest) (*GraphResponse, error) -} - -func RegisterDGraphServer(s *grpc.Server, srv DGraphServer) { - s.RegisterService(&_DGraph_serviceDesc, srv) -} - -func _DGraph_Query_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(GraphRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(DGraphServer).Query(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/pb.DGraph/Query", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(DGraphServer).Query(ctx, req.(*GraphRequest)) - } - return interceptor(ctx, in, info, handler) -} - -var _DGraph_serviceDesc = grpc.ServiceDesc{ - ServiceName: "pb.DGraph", - HandlerType: (*DGraphServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "Query", - Handler: _DGraph_Query_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, -} - -var fileDescriptor0 = []byte{ - // 255 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x64, 0x90, 0x4f, 0x4b, 0xc4, 0x30, - 0x10, 0xc5, 0xed, 0xfe, 0x89, 0x76, 0x76, 0x05, 0x1d, 0x45, 0x8a, 0x28, 0x48, 0xf0, 0xb0, 0x1e, - 0xec, 0x61, 0xbd, 0xf8, 0x01, 0x04, 0x0f, 0x7a, 0x71, 0xc0, 0x0f, 0xd0, 0xda, 0xe0, 0x06, 0xea, - 0x36, 0x26, 0xa9, 0xe8, 0xcd, 0x8f, 0xee, 0x34, 0x09, 0xae, 0xb2, 0xb7, 0x99, 0xbc, 0x97, 0xf7, - 0x7e, 0x0c, 0x1c, 0xbd, 0xda, 0xca, 0xac, 0xac, 0x72, 0xa6, 0x5b, 0x3b, 0x55, 0x1a, 0xdb, 0xf9, - 0x0e, 0x47, 0xa6, 0x96, 0xe7, 0xb0, 0xfb, 0xac, 0x9b, 0x47, 0xed, 0x3c, 0x22, 0x4c, 0x7a, 0xdd, - 0xb8, 0x22, 0xbb, 0x18, 0x2f, 0x26, 0x14, 0x66, 0xf9, 0x00, 0x82, 0x94, 0xeb, 0x5b, 0x8f, 0x27, - 0x20, 0x3e, 0xaa, 0xb6, 0x57, 0x51, 0x9f, 0x53, 0xda, 0xf0, 0x0a, 0x72, 0x76, 0xbe, 0x55, 0xde, - 0xea, 0xcf, 0x62, 0xc4, 0xd2, 0x6c, 0x39, 0x2b, 0x4d, 0x5d, 0xa6, 0x54, 0xda, 0xa8, 0xf2, 0x12, - 0xe6, 0xf7, 0x03, 0x06, 0xa9, 0x77, 0xfe, 0xe9, 0xf1, 0x18, 0xa6, 0x3c, 0xd8, 0x2f, 0x4e, 0xcc, - 0x16, 0x39, 0xc5, 0x45, 0x7e, 0x67, 0xb0, 0x9f, 0x6c, 0x91, 0x16, 0xcf, 0x20, 0xaf, 0x3c, 0x27, - 0xd4, 0xbd, 0x57, 0xc9, 0xbb, 0x79, 0x40, 0x09, 0xc2, 0x06, 0x44, 0x6e, 0xcf, 0xb8, 0x1d, 0x86, - 0xf6, 0x08, 0x4d, 0x49, 0xc1, 0x6b, 0xd8, 0x7b, 0x59, 0xe9, 0xb6, 0xb1, 0x6a, 0x5d, 0x8c, 0x03, - 0xe3, 0xe1, 0xe0, 0xfa, 0x57, 0x43, 0xbf, 0x96, 0xe5, 0x2d, 0x88, 0xbb, 0xa0, 0x61, 0x09, 0xd3, - 0xa7, 0x81, 0x0a, 0x0f, 0xfe, 0xf8, 0x03, 0xfd, 0xe9, 0x76, 0x82, 0xdc, 0xa9, 0x45, 0xb8, 0xec, - 0xcd, 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xd9, 0x42, 0x7b, 0x6e, 0x70, 0x01, 0x00, 0x00, -} diff --git a/query/pb/graphresponse.proto b/query/pb/graphresponse.proto deleted file mode 100644 index f13499b9724f2330a951d10f7f10ceff5a137921..0000000000000000000000000000000000000000 --- a/query/pb/graphresponse.proto +++ /dev/null @@ -1,25 +0,0 @@ -syntax="proto3"; -package pb; - -service DGraph { - rpc Query (GraphRequest) returns (GraphResponse) {} -} - -message UidList { - repeated uint64 uids = 1; -} - -message Result { - repeated bytes values = 1; - repeated UidList uidmatrix = 2; -} - -message GraphRequest { - string query = 1; -} - -message GraphResponse { - string attribute = 1; - Result result = 2; - repeated GraphResponse children = 3; // Each node can have multiple children -} diff --git a/query/query.go b/query/query.go index ee2643e0364134761b3c55015709a02930e9e3dd..19ea07f8f40aef96f6f21d80af8a561d24ddaac9 100644 --- a/query/query.go +++ b/query/query.go @@ -26,7 +26,7 @@ import ( "github.com/Sirupsen/logrus" "github.com/dgraph-io/dgraph/gql" "github.com/dgraph-io/dgraph/posting" - "github.com/dgraph-io/dgraph/query/pb" + "github.com/dgraph-io/dgraph/query/graph" "github.com/dgraph-io/dgraph/task" "github.com/dgraph-io/dgraph/worker" "github.com/dgraph-io/dgraph/x" @@ -89,10 +89,11 @@ import ( var glog = x.Log("query") type Latency struct { - Start time.Time `json:"-"` - Parsing time.Duration `json:"query_parsing"` - Processing time.Duration `json:"processing"` - Json time.Duration `json:"json_conversion"` + Start time.Time `json:"-"` + Parsing time.Duration `json:"query_parsing"` + Processing time.Duration `json:"processing"` + Json time.Duration `json:"json_conversion"` + ProtocolBuffer time.Duration `json:"pb_conversion"` } func (l *Latency) ToMap() map[string]string { @@ -257,73 +258,121 @@ func (g *SubGraph) ToJson(l *Latency) (js []byte, rerr error) { return json.Marshal(r) } -// This method take in a flatbuffer result, extracts values and uids from it -// and converts it to a protocol buffer result -func extract(r *task.Result) (*pb.Result, error) { - var result = &pb.Result{} - var ul task.UidList - for i := 0; i < r.UidmatrixLength(); i++ { - if ok := r.Uidmatrix(&ul, i); !ok { - return result, fmt.Errorf("While parsing UidList") - } - - uidList := &pb.UidList{} - for j := 0; j < ul.UidsLength(); j++ { - uid := ul.Uids(j) - uidList.Uids = append(uidList.Uids, uid) +// This function performs a binary search on the uids slice and returns the +// index at which it finds the uid, else returns -1 +func indexOf(uid uint64, q *task.Query) int { + low, mid, high := 0, 0, q.UidsLength()-1 + for low <= high { + mid = (low + high) / 2 + if q.Uids(mid) == uid { + return mid + } else if q.Uids(mid) > uid { + high = mid - 1 + } else { + low = mid + 1 } - result.Uidmatrix = append(result.Uidmatrix, uidList) } + return -1 +} - var tv task.Value - for i := 0; i < r.ValuesLength(); i++ { - if ok := r.Values(&tv, i); !ok { - return result, fmt.Errorf("While parsing value") +// This method gets the values and children for a subgraph. +func (g *SubGraph) preTraverse(uid uint64, dst *graph.Node) error { + properties := make(map[string]*graph.Value) + var children []*graph.Node + + // We go through all predicate children of the subgraph. + for _, pc := range g.Children { + ro := flatbuffers.GetUOffsetT(pc.result) + r := new(task.Result) + r.Init(pc.result, ro) + + uo := flatbuffers.GetUOffsetT(pc.query) + q := new(task.Query) + q.Init(pc.query, uo) + + idx := indexOf(uid, q) + + if idx == -1 { + glog.WithFields(logrus.Fields{ + "uid": uid, + "attribute": g.Attr, + "childAttribute": pc.Attr, + }).Fatal("Attribute with uid not found in child Query uids") + return fmt.Errorf("Attribute with uid not found") } - var ival interface{} - if err := posting.ParseValue(&ival, tv.ValBytes()); err != nil { - return result, err + var ul task.UidList + var tv task.Value + if ok := r.Uidmatrix(&ul, idx); !ok { + return fmt.Errorf("While parsing UidList") } - if ival == nil { - ival = "" + if ul.UidsLength() > 0 { + // We create as many predicate entity children as the length of uids for + // this predicate. + for i := 0; i < ul.UidsLength(); i++ { + uid := ul.Uids(i) + uc := new(graph.Node) + uc.Attribute = pc.Attr + uc.Uid = uid + if rerr := pc.preTraverse(uid, uc); rerr != nil { + x.Err(glog, rerr).Error("Error while traversal") + return rerr + } + + children = append(children, uc) + } + } else { + v := new(graph.Value) + if ok := r.Values(&tv, idx); !ok { + return fmt.Errorf("While parsing value") + } + + var ival interface{} + if err := posting.ParseValue(&ival, tv.ValBytes()); err != nil { + return err + } + + if ival == nil { + ival = "" + } + + v.Str = ival.(string) + properties[pc.Attr] = v } - result.Values = append(result.Values, []byte(ival.(string))) } - return result, nil + if val, ok := properties["_xid_"]; ok { + dst.Xid = val.Str + delete(properties, "_xid_") + } + dst.Properties, dst.Children = properties, children + return nil } -// This method performs a pre traversal on a subgraph and converts it to a -// protocol buffer Graph Response. -func (g *SubGraph) PreTraverse() (gr *pb.GraphResponse, rerr error) { - gr = &pb.GraphResponse{} +// This method transforms the predicate based subgraph to an +// predicate-entity based protocol buffer subgraph. +func (g *SubGraph) ToProtocolBuffer(l *Latency) (n *graph.Node, rerr error) { + n = &graph.Node{} + n.Attribute = g.Attr if len(g.query) == 0 { - return gr, nil + return n, nil } - gr.Attribute = g.Attr ro := flatbuffers.GetUOffsetT(g.result) r := new(task.Result) r.Init(g.result, ro) - result, err := extract(r) - if err != nil { - return gr, err - } - - gr.Result = result - - for _, child := range g.Children { - childPb, err := child.PreTraverse() - if err != nil { - x.Err(glog, err).Error("Error while traversal") - return gr, err - } + var ul task.UidList + r.Uidmatrix(&ul, 0) + n.Uid = ul.Uids(0) - gr.Children = append(gr.Children, childPb) + if rerr = g.preTraverse(n.Uid, n); rerr != nil { + x.Err(glog, rerr).Error("Error while traversal") + return n, rerr } - return gr, nil + + l.ProtocolBuffer = time.Since(l.Start) - l.Parsing - l.Processing + return n, nil } func treeCopy(gq *gql.GraphQuery, sg *SubGraph) { diff --git a/query/query_test.go b/query/query_test.go index 7cf511dcb9405725d0c78833be8cd3fe757f7c4a..01a676da31e89d3e0774ec0de3cc6c5062872a7a 100644 --- a/query/query_test.go +++ b/query/query_test.go @@ -184,6 +184,9 @@ func populateGraph(t *testing.T) (string, *store.Store) { edge.Value = "Andrea" addEdge(t, edge, posting.GetOrCreate(posting.Key(31, "name"), ps)) + edge.Value = "mich" + addEdge(t, edge, posting.GetOrCreate(posting.Key(1, "_xid_"), ps)) + return dir, ps } @@ -320,19 +323,22 @@ func TestToJson(t *testing.T) { fmt.Printf(string(js)) } -func TestPreTraverse(t *testing.T) { +func TestToProtocolBuffer(t *testing.T) { dir, _ := populateGraph(t) defer os.RemoveAll(dir) query := ` { me(_uid_:0x01) { + _xid_ name gender status friend { name } + friend { + } } } ` @@ -353,41 +359,64 @@ func TestPreTraverse(t *testing.T) { t.Error(err) } - ugr, err := sg.PreTraverse() + var l Latency + gr, err := sg.ToProtocolBuffer(&l) if err != nil { t.Error(err) } - if len(ugr.Children) != 4 { - t.Errorf("Expected len 4. Got: %v", ugr.Children) + if gr.Attribute != "_root_" { + t.Errorf("Expected attribute _root_, Got: %v", gr.Attribute) } - child := ugr.Children[0] - if child.Attribute != "name" { - t.Errorf("Expected attr name. Got: %v", child.Attribute) + if gr.Uid != 1 { + t.Errorf("Expected uid 1, Got: %v", gr.Uid) } - if string(child.Result.Values[0]) != "Michonne" { - t.Errorf("Expected value Michonne. Got %v", - string(child.Result.Values[0])) + if gr.Xid != "mich" { + t.Errorf("Expected xid mich, Got: %v", gr.Xid) } - child = ugr.Children[3] - if child.Attribute != "friend" { - t.Errorf("Expected attr friend. Got: %v", child.Attribute) + if len(gr.Properties) != 3 { + t.Errorf("Expected values map to contain 3 properties, Got: %v", + len(gr.Properties)) } - uids := child.Result.Uidmatrix[0].Uids - if uids[0] != 23 || uids[1] != 24 || uids[2] != 25 || uids[3] != 31 || - uids[4] != 101 { - t.Errorf("Friend ids don't match") + if gr.Properties["name"].Str != "Michonne" { + t.Errorf("Expected property name to have value Michonne, Got: %v", + gr.Properties["name"].Str) } - // To check for name of friends - child = child.Children[0] - if child.Attribute != "name" { - t.Errorf("Expected attr friend. Got: %v", child.Attribute) + if len(gr.Children) != 10 { + t.Errorf("Expected 10 children, Got: %v", len(gr.Children)) } - names := child.Result.Values + child := gr.Children[0] + if child.Uid != 23 { + t.Errorf("Expected uid 23, Got: %v", gr.Uid) + } + if child.Attribute != "friend" { + t.Errorf("Expected attribute friend, Got: %v", child.Attribute) + } + if len(child.Properties) != 1 { + t.Errorf("Expected values map to contain 1 property, Got: %v", + len(child.Properties)) + } + if child.Properties["name"].Str != "Rick Grimes" { + t.Errorf("Expected property name to have value Rick Grimes, Got: %v", + child.Properties["name"].Str) + } + if len(child.Children) != 0 { + t.Errorf("Expected 0 children, Got: %v", len(child.Children)) + } - if string(names[0]) != "Rick Grimes" || string(names[1]) != "Glenn Rhee" || - string(names[2]) != "Daryl Dixon" || string(names[3]) != "Andrea" { - t.Errorf("Names don't match") + child = gr.Children[5] + if child.Uid != 23 { + t.Errorf("Expected uid 23, Got: %v", gr.Uid) + } + if child.Attribute != "friend" { + t.Errorf("Expected attribute friend, Got: %v", child.Attribute) + } + if len(child.Properties) != 0 { + t.Errorf("Expected values map to contain 0 properties, Got: %v", + len(child.Properties)) + } + if len(child.Children) != 0 { + t.Errorf("Expected 0 children, Got: %v", len(child.Children)) } } diff --git a/server/main.go b/server/main.go index 3004149900f5cab41e677d683cf7ef62d54b928e..1cea3b82a86cef92c58184bfccff285f378927f1 100644 --- a/server/main.go +++ b/server/main.go @@ -36,7 +36,7 @@ import ( "github.com/dgraph-io/dgraph/gql" "github.com/dgraph-io/dgraph/posting" "github.com/dgraph-io/dgraph/query" - "github.com/dgraph-io/dgraph/query/pb" + "github.com/dgraph-io/dgraph/query/graph" "github.com/dgraph-io/dgraph/rdf" "github.com/dgraph-io/dgraph/store" "github.com/dgraph-io/dgraph/uid" @@ -203,19 +203,21 @@ func queryHandler(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, string(js)) } -// server is used to implement pb.DGraphServer +// server is used to implement graph.DGraphServer type server struct{} // This method is used to execute the query and return the response to the // client as a protocol buffer message. func (s *server) Query(ctx context.Context, - req *pb.GraphRequest) (*pb.GraphResponse, error) { - resp := new(pb.GraphResponse) + req *graph.Request) (*graph.Node, error) { + resp := new(graph.Node) if len(req.Query) == 0 { glog.Error("While reading query") return resp, fmt.Errorf("Empty query") } + var l query.Latency + l.Start = time.Now() // TODO(pawan): Refactor query parsing and graph processing code to a common // function used by Query and queryHandler glog.WithField("q", req.Query).Debug("Query received.") @@ -230,6 +232,7 @@ func (s *server) Query(ctx context.Context, x.Err(glog, err).Error("While conversion to internal format") return resp, err } + l.Parsing = time.Since(l.Start) glog.WithField("q", req.Query).Debug("Query parsed.") rch := make(chan error) @@ -239,9 +242,10 @@ func (s *server) Query(ctx context.Context, x.Err(glog, err).Error("While executing query") return resp, err } - + l.Processing = time.Since(l.Start) - l.Parsing glog.WithField("q", req.Query).Debug("Graph processed.") - resp, err = sg.PreTraverse() + + resp, err = sg.ToProtocolBuffer(&l) if err != nil { x.Err(glog, err).Error("While converting to protocol buffer.") return resp, err @@ -261,7 +265,7 @@ func runGrpcServer(address string) { glog.WithField("address", ln.Addr()).Info("Client Worker listening") s := grpc.NewServer() - pb.RegisterDGraphServer(s, &server{}) + graph.RegisterDGraphServer(s, &server{}) if err = s.Serve(ln); err != nil { glog.Fatalf("While serving gRpc requests", err) }