diff --git a/core/api.go b/core/api.go index e4437f6..c3b0963 100644 --- a/core/api.go +++ b/core/api.go @@ -85,10 +85,10 @@ type SuperGraph struct { allowList *allow.List encKey [32]byte hashSeed maphash.Seed - queries map[uint64]*query + queries map[uint64]query roles map[string]*Role getRole *sql.Stmt - rmap map[uint64]*resolvFn + rmap map[uint64]resolvFn abacEnabled bool anonExists bool qc *qcode.Compiler diff --git a/core/core.go b/core/core.go index 3f01004..9c9d7f3 100644 --- a/core/core.go +++ b/core/core.go @@ -179,7 +179,7 @@ func (c *scontext) resolvePreparedSQL() ([]byte, *stmt, error) { } if q.sd == nil { - q.Do(func() { c.sg.prepare(q, role) }) + q.Do(func() { c.sg.prepare(&q, role) }) if q.err != nil { return nil, nil, err @@ -196,6 +196,8 @@ func (c *scontext) resolvePreparedSQL() ([]byte, *stmt, error) { return nil, nil, err } + fmt.Println(">>", varsList) + if useTx { row = tx.Stmt(q.sd).QueryRow(varsList...) } else { diff --git a/core/prepare.go b/core/prepare.go index d91ab23..2f6f235 100644 --- a/core/prepare.go +++ b/core/prepare.go @@ -63,7 +63,7 @@ func (sg *SuperGraph) initPrepared() error { return fmt.Errorf("role query: %w", err) } - sg.queries = make(map[uint64]*query) + sg.queries = make(map[uint64]query) list, err := sg.allowList.Load() if err != nil { @@ -77,22 +77,19 @@ func (sg *SuperGraph) initPrepared() error { if len(v.Query) == 0 { continue } - q := &query{ai: v, qt: qcode.GetQType(v.Query)} + qt := qcode.GetQType(v.Query) - switch q.qt { + switch qt { case qcode.QTQuery: - sg.queries[queryID(&h, v.Name, "user")] = q - h.Reset() + sg.queries[queryID(&h, v.Name, "user")] = query{ai: v, qt: qt} if sg.anonExists { - sg.queries[queryID(&h, v.Name, "anon")] = q - h.Reset() + sg.queries[queryID(&h, v.Name, "anon")] = query{ai: v, qt: qt} } case qcode.QTMutation: for _, role := range sg.conf.Roles { - sg.queries[queryID(&h, v.Name, role.Name)] = q - h.Reset() + sg.queries[queryID(&h, v.Name, role.Name)] = query{ai: v, qt: qt} } } } @@ -166,5 +163,8 @@ func (sg *SuperGraph) initAllowList() error { func queryID(h *maphash.Hash, name string, role string) uint64 { h.WriteString(name) h.WriteString(role) - return h.Sum64() + v := h.Sum64() + h.Reset() + + return v } diff --git a/core/remote.go b/core/remote.go index d184394..e905520 100644 --- a/core/remote.go +++ b/core/remote.go @@ -4,10 +4,10 @@ import ( "bytes" "errors" "fmt" + "hash/maphash" "net/http" "sync" - "github.com/cespare/xxhash/v2" "github.com/dosco/super-graph/core/internal/qcode" "github.com/dosco/super-graph/jsn" ) @@ -16,12 +16,13 @@ func (sg *SuperGraph) execRemoteJoin(st *stmt, data []byte, hdr http.Header) ([] var err error sel := st.qc.Selects - h := xxhash.New() + h := maphash.Hash{} + h.SetSeed(sg.hashSeed) // fetch the field name used within the db response json // that are used to mark insertion points and the mapping between // those field names and their select objects - fids, sfmap := sg.parentFieldIds(h, sel, st.md.Skipped) + fids, sfmap := sg.parentFieldIds(&h, sel, st.md.Skipped) // fetch the field values of the marked insertion points // these values contain the id to be used with fetching remote data @@ -30,10 +31,10 @@ func (sg *SuperGraph) execRemoteJoin(st *stmt, data []byte, hdr http.Header) ([] switch { case len(from) == 1: - to, err = sg.resolveRemote(hdr, h, from[0], sel, sfmap) + to, err = sg.resolveRemote(hdr, &h, from[0], sel, sfmap) case len(from) > 1: - to, err = sg.resolveRemotes(hdr, h, from, sel, sfmap) + to, err = sg.resolveRemotes(hdr, &h, from, sel, sfmap) default: return nil, errors.New("something wrong no remote ids found in db response") @@ -55,7 +56,7 @@ func (sg *SuperGraph) execRemoteJoin(st *stmt, data []byte, hdr http.Header) ([] func (sg *SuperGraph) resolveRemote( hdr http.Header, - h *xxhash.Digest, + h *maphash.Hash, field jsn.Field, sel []qcode.Select, sfmap map[uint64]*qcode.Select) ([]jsn.Field, error) { @@ -66,7 +67,8 @@ func (sg *SuperGraph) resolveRemote( to := toA[:1] // use the json key to find the related Select object - k1 := xxhash.Sum64(field.Key) + h.Write(field.Key) + k1 := h.Sum64() s, ok := sfmap[k1] if !ok { @@ -117,7 +119,7 @@ func (sg *SuperGraph) resolveRemote( func (sg *SuperGraph) resolveRemotes( hdr http.Header, - h *xxhash.Digest, + h *maphash.Hash, from []jsn.Field, sel []qcode.Select, sfmap map[uint64]*qcode.Select) ([]jsn.Field, error) { @@ -134,7 +136,8 @@ func (sg *SuperGraph) resolveRemotes( for i, id := range from { // use the json key to find the related Select object - k1 := xxhash.Sum64(id.Key) + h.Write(id.Key) + k1 := h.Sum64() s, ok := sfmap[k1] if !ok { @@ -192,7 +195,7 @@ func (sg *SuperGraph) resolveRemotes( return to, cerr } -func (sg *SuperGraph) parentFieldIds(h *xxhash.Digest, sel []qcode.Select, skipped uint32) ( +func (sg *SuperGraph) parentFieldIds(h *maphash.Hash, sel []qcode.Select, skipped uint32) ( [][]byte, map[uint64]*qcode.Select) { @@ -227,8 +230,8 @@ func (sg *SuperGraph) parentFieldIds(h *xxhash.Digest, sel []qcode.Select, skipp fm[n] = r.IDField n++ - k := xxhash.Sum64(r.IDField) - sm[k] = s + h.Write(r.IDField) + sm[h.Sum64()] = s } } diff --git a/core/resolve.go b/core/resolve.go index 08671e2..bdb4857 100644 --- a/core/resolve.go +++ b/core/resolve.go @@ -2,11 +2,11 @@ package core import ( "fmt" + "hash/maphash" "io/ioutil" "net/http" "strings" - "github.com/cespare/xxhash/v2" "github.com/dosco/super-graph/core/internal/psql" "github.com/dosco/super-graph/jsn" ) @@ -19,7 +19,7 @@ type resolvFn struct { func (sg *SuperGraph) initResolvers() error { var err error - sg.rmap = make(map[uint64]*resolvFn) + sg.rmap = make(map[uint64]resolvFn) for _, t := range sg.conf.Tables { err = sg.initRemotes(t) @@ -36,7 +36,8 @@ func (sg *SuperGraph) initResolvers() error { } func (sg *SuperGraph) initRemotes(t Table) error { - h := xxhash.New() + h := maphash.Hash{} + h.SetSeed(sg.hashSeed) for _, r := range t.Remotes { // defines the table column to be used as an id in the @@ -75,17 +76,18 @@ func (sg *SuperGraph) initRemotes(t Table) error { path = append(path, []byte(p)) } - rf := &resolvFn{ + rf := resolvFn{ IDField: []byte(idk), Path: path, Fn: fn, } // index resolver obj by parent and child names - sg.rmap[mkkey(h, r.Name, t.Name)] = rf + sg.rmap[mkkey(&h, r.Name, t.Name)] = rf // index resolver obj by IDField - sg.rmap[xxhash.Sum64(rf.IDField)] = rf + h.Write(rf.IDField) + sg.rmap[h.Sum64()] = rf } return nil diff --git a/core/utils.go b/core/utils.go index c4e0147..4de98a1 100644 --- a/core/utils.go +++ b/core/utils.go @@ -1,11 +1,9 @@ package core -import ( - "github.com/cespare/xxhash/v2" -) +import "hash/maphash" // nolint: errcheck -func mkkey(h *xxhash.Digest, k1 string, k2 string) uint64 { +func mkkey(h *maphash.Hash, k1 string, k2 string) uint64 { h.WriteString(k1) h.WriteString(k2) v := h.Sum64() diff --git a/docs/website/docusaurus.config.js b/docs/website/docusaurus.config.js index 3695ea0..70f9c9e 100644 --- a/docs/website/docusaurus.config.js +++ b/docs/website/docusaurus.config.js @@ -36,8 +36,8 @@ module.exports = { position: "left", }, { - label: "Art Compute", - href: "https://artcompute.com/s/super-graph", + label: "AbtCode", + href: "https://abtcode.com/s/super-graph", position: "left", }, ], diff --git a/go.mod b/go.mod index 397ca5b..b5e23a1 100644 --- a/go.mod +++ b/go.mod @@ -12,13 +12,11 @@ require ( github.com/adjust/gorails v0.0.0-20171013043634-2786ed0c03d3 github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b github.com/brianvoe/gofakeit/v5 v5.2.0 - github.com/cespare/xxhash/v2 v2.1.1 github.com/chirino/graphql v0.0.0-20200430165312-293648399b1a github.com/daaku/go.zipexe v1.0.1 // indirect github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/dlclark/regexp2 v1.2.0 // indirect github.com/dop251/goja v0.0.0-20200424152103-d0b8fda54cd0 - github.com/dvyukov/go-fuzz v0.0.0-20200318091601-be3528f3a813 // indirect github.com/fsnotify/fsnotify v1.4.9 github.com/garyburd/redigo v1.6.0 github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect @@ -30,7 +28,6 @@ require ( github.com/openzipkin/zipkin-go v0.2.2 github.com/pelletier/go-toml v1.7.0 // indirect github.com/pkg/errors v0.9.1 - github.com/prometheus/common v0.4.0 github.com/rs/cors v1.7.0 github.com/spf13/afero v1.2.2 // indirect github.com/spf13/cast v1.3.1 // indirect diff --git a/go.sum b/go.sum index 5b86744..eb59e11 100644 --- a/go.sum +++ b/go.sum @@ -55,8 +55,6 @@ github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chirino/graphql v0.0.0-20200430165312-293648399b1a h1:WVu7r2vwlrBVmunbSSU+9/3M3AgsQyhE49CKDjHiFq4= github.com/chirino/graphql v0.0.0-20200430165312-293648399b1a/go.mod h1:wQjjxFMFyMlsWh4Z3nMuHQtevD4Ul9UVQSnz1JOLuP8= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= @@ -87,8 +85,6 @@ github.com/dlclark/regexp2 v1.2.0 h1:8sAhBGEM0dRWogWqWyQeIJnxjWO6oIjl8FKqREDsGfk github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/dop251/goja v0.0.0-20200424152103-d0b8fda54cd0 h1:EfFAcaAwGai/wlDCWwIObHBm3T2C2CCPX/SaS0fpOJ4= github.com/dop251/goja v0.0.0-20200424152103-d0b8fda54cd0/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA= -github.com/dvyukov/go-fuzz v0.0.0-20200318091601-be3528f3a813 h1:NgO45/5mBLRVfiXerEFzH6ikcZ7DNRPS639xFg3ENzU= -github.com/dvyukov/go-fuzz v0.0.0-20200318091601-be3528f3a813/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= diff --git a/internal/serv/cmd_seed.go b/internal/serv/cmd_seed.go index 9fac3ff..21bb954 100644 --- a/internal/serv/cmd_seed.go +++ b/internal/serv/cmd_seed.go @@ -82,8 +82,6 @@ func graphQLFunc(sg *core.SuperGraph, query string, data interface{}, opt map[st if v, ok := opt["user_id"]; ok && len(v) != 0 { ct = context.WithValue(ct, core.UserIDKey, v) - } else { - ct = context.WithValue(ct, core.UserIDKey, "-1") } // var role string diff --git a/jsn/bench.1 b/jsn/bench.1 new file mode 100644 index 0000000..b3c424c --- /dev/null +++ b/jsn/bench.1 @@ -0,0 +1,13 @@ +goos: darwin +goarch: amd64 +pkg: github.com/dosco/super-graph/jsn +BenchmarkGet +BenchmarkGet-16 13898 85293 ns/op 3328 B/op 2 allocs/op +BenchmarkFilter +BenchmarkFilter-16 189328 6341 ns/op 448 B/op 1 allocs/op +BenchmarkStrip +BenchmarkStrip-16 219765 5543 ns/op 224 B/op 1 allocs/op +BenchmarkReplace +BenchmarkReplace-16 100899 12022 ns/op 416 B/op 1 allocs/op +PASS +ok github.com/dosco/super-graph/jsn 6.029s diff --git a/jsn/filter.go b/jsn/filter.go index 3772a91..6b9c6dd 100644 --- a/jsn/filter.go +++ b/jsn/filter.go @@ -2,17 +2,19 @@ package jsn import ( "bytes" - - "github.com/cespare/xxhash/v2" + "hash/maphash" ) // Filter function filters the JSON keeping only the provided keys and removing all others func Filter(w *bytes.Buffer, b []byte, keys []string) error { var err error kmap := make(map[uint64]struct{}, len(keys)) + h := maphash.Hash{} for i := range keys { - kmap[xxhash.Sum64String(keys[i])] = struct{}{} + h.WriteString(keys[i]) + kmap[h.Sum64()] = struct{}{} + h.Reset() } // is an list @@ -132,7 +134,11 @@ func Filter(w *bytes.Buffer, b []byte, keys []string) error { cb := b[s:(e + 1)] e = 0 - if _, ok := kmap[xxhash.Sum64(k)]; !ok { + h.Write(k) + _, ok := kmap[h.Sum64()] + h.Reset() + + if !ok { continue } diff --git a/jsn/get.go b/jsn/get.go index 7e2d8fe..52f00ed 100644 --- a/jsn/get.go +++ b/jsn/get.go @@ -1,7 +1,7 @@ package jsn import ( - "github.com/cespare/xxhash/v2" + "hash/maphash" ) const ( @@ -41,9 +41,12 @@ func Value(b []byte) []byte { // Keys function fetches values for the provided keys func Get(b []byte, keys [][]byte) []Field { kmap := make(map[uint64]struct{}, len(keys)) + h := maphash.Hash{} for i := range keys { - kmap[xxhash.Sum64(keys[i])] = struct{}{} + h.Write(keys[i]) + kmap[h.Sum64()] = struct{}{} + h.Reset() } res := make([]Field, 0, 20) @@ -141,7 +144,9 @@ func Get(b []byte, keys [][]byte) []Field { } if e != 0 { - _, ok := kmap[xxhash.Sum64(k)] + h.Write(k) + _, ok := kmap[h.Sum64()] + h.Reset() if ok { res = append(res, Field{k, b[s:(e + 1)]}) diff --git a/jsn/replace.go b/jsn/replace.go index 3a7ceaf..f00f640 100644 --- a/jsn/replace.go +++ b/jsn/replace.go @@ -3,8 +3,7 @@ package jsn import ( "bytes" "errors" - - "github.com/cespare/xxhash/v2" + "hash/maphash" ) // Replace function replaces key-value pairs provided in the `from` argument with those in the `to` argument @@ -18,7 +17,7 @@ func Replace(w *bytes.Buffer, b []byte, from, to []Field) error { return err } - h := xxhash.New() + h := maphash.Hash{} tmap := make(map[uint64]int, len(from)) for i, f := range from {