Skip to content

Commit 5cd5bff

Browse files
authored
perf(core): Add sharded map for post query speedup (#9431)
1 parent 5851889 commit 5cd5bff

File tree

9 files changed

+409
-183
lines changed

9 files changed

+409
-183
lines changed

dql/math.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ type MathTree struct {
4949
Fn string
5050
Var string
5151
Const types.Val // This will always be parsed as a float value
52-
Val map[uint64]types.Val
52+
Val *types.ShardedMap
5353
Child []*MathTree
5454
}
5555

edgraph/server.go

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -834,7 +834,7 @@ func findMutationVars(qc *queryContext) []string {
834834
// If val(variable) exists in a query, but the values are not there for the variable,
835835
// it will ignore the mutation silently.
836836
func updateValInNQuads(nquads []*api.NQuad, qc *queryContext, isSet bool) []*api.NQuad {
837-
getNewVals := func(s string) (map[uint64]types.Val, bool) {
837+
getNewVals := func(s string) (*types.ShardedMap, bool) {
838838
if strings.HasPrefix(s, "val(") {
839839
varName := s[4 : len(s)-1]
840840
if v, ok := qc.valRes[varName]; ok && v != nil {
@@ -845,15 +845,15 @@ func updateValInNQuads(nquads []*api.NQuad, qc *queryContext, isSet bool) []*api
845845
return nil, false
846846
}
847847

848-
getValue := func(key uint64, uidToVal map[uint64]types.Val) (types.Val, bool) {
849-
val, ok := uidToVal[key]
848+
getValue := func(key uint64, uidToVal *types.ShardedMap) (types.Val, bool) {
849+
val, ok := uidToVal.Get(key)
850850
if ok {
851851
return val, true
852852
}
853853

854854
// Check if the variable is aggregate variable
855855
// Only 0 key would exist for aggregate variable
856-
val, ok = uidToVal[0]
856+
val, ok = uidToVal.Get(0)
857857
return val, ok
858858
}
859859

@@ -1026,7 +1026,7 @@ type queryContext struct {
10261026
uidRes map[string][]string
10271027
// valRes stores mapping from variable names to values for value
10281028
// variables used in the mutation block of incoming request.
1029-
valRes map[string]map[uint64]types.Val
1029+
valRes map[string]*types.ShardedMap
10301030
// l stores latency numbers
10311031
latency *query.Latency
10321032
// span stores a opencensus span used throughout the query processing
@@ -1494,10 +1494,11 @@ func processQuery(ctx context.Context, qc *queryContext) (*api.Response, error)
14941494
if v.Uids != nil && len(v.Uids.Uids) > 0 {
14951495
uidList = v.Uids.Uids
14961496
} else {
1497-
uidList = make([]uint64, 0, len(v.Vals))
1498-
for uid := range v.Vals {
1497+
uidList = make([]uint64, 0, v.Vals.Len())
1498+
v.Vals.Iterate(func(uid uint64, val types.Val) error {
14991499
uidList = append(uidList, uid)
1500-
}
1500+
return nil
1501+
})
15011502
}
15021503
if len(uidList) == 0 {
15031504
continue
@@ -1565,7 +1566,7 @@ func parseRequest(ctx context.Context, qc *queryContext) error {
15651566
}
15661567

15671568
qc.uidRes = make(map[string][]string)
1568-
qc.valRes = make(map[string]map[uint64]types.Val)
1569+
qc.valRes = make(map[string]*types.ShardedMap)
15691570
upsertQuery = buildUpsertQuery(qc)
15701571
needVars = findMutationVars(qc)
15711572
if upsertQuery == "" {
@@ -1627,19 +1628,24 @@ func verifyUnique(qc *queryContext, qr query.Request) error {
16271628
var predValue interface{}
16281629
if strings.HasPrefix(pred.ObjectId, "val(") {
16291630
varName := qr.Vars[pred.ObjectId[4:len(pred.ObjectId)-1]]
1630-
val, ok := varName.Vals[0]
1631+
val, ok := varName.Vals.Get(0)
16311632
if !ok {
1632-
_, isValueGoingtoSet := varName.Vals[subjectUid]
1633+
_, isValueGoingtoSet := varName.Vals.Get(subjectUid)
16331634
if !isValueGoingtoSet {
16341635
continue
16351636
}
16361637

16371638
results := qr.Vars[queryVar.valVar]
1638-
for uidOfv, v := range results.Vals {
1639-
if v.Value == varName.Vals[subjectUid].Value && uidOfv != subjectUid {
1639+
err := results.Vals.Iterate(func(uidOfv uint64, v types.Val) error {
1640+
varNameVal, _ := varName.Vals.Get(subjectUid)
1641+
if v.Value == varNameVal.Value && uidOfv != subjectUid {
16401642
return errors.Errorf("could not insert duplicate value [%v] for predicate [%v]",
16411643
v.Value, pred.Predicate)
16421644
}
1645+
return nil
1646+
})
1647+
if err != nil {
1648+
return err
16431649
}
16441650
continue
16451651
} else {

query/groupby.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@ func (sg *SubGraph) fillGroupedVars(doneVars map[string]varValue, path []*SubGra
334334
}
335335
chVar := child.Params.Var
336336

337-
tempMap := make(map[uint64]types.Val)
337+
tempMap := types.NewShardedMap()
338338
for _, grp := range res.group {
339339
if len(grp.keys) == 0 {
340340
continue
@@ -349,7 +349,7 @@ func (sg *SubGraph) fillGroupedVars(doneVars map[string]varValue, path []*SubGra
349349
}
350350
// grp.aggregates could be empty if schema conversion failed during aggregation
351351
if len(grp.aggregates) > 0 {
352-
tempMap[uid] = grp.aggregates[len(grp.aggregates)-1].key
352+
tempMap.Set(uid, grp.aggregates[len(grp.aggregates)-1].key)
353353
}
354354
}
355355
doneVars[chVar] = varValue{

query/math.go

Lines changed: 58 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
package query
77

88
import (
9+
"sync"
10+
911
"github.com/golang/glog"
1012
"github.com/pkg/errors"
1113

@@ -16,7 +18,7 @@ type mathTree struct {
1618
Fn string
1719
Var string
1820
Const types.Val // If its a const value node.
19-
Val map[uint64]types.Val
21+
Val *types.ShardedMap
2022
Child []*mathTree
2123
}
2224

@@ -36,24 +38,23 @@ var (
3638
// processBinary handles the binary operands like
3739
// +, -, *, /, %, max, min, logbase, dot
3840
func processBinary(mNode *mathTree) error {
39-
destMap := make(map[uint64]types.Val)
4041
aggName := mNode.Fn
4142

4243
mpl := mNode.Child[0].Val
4344
mpr := mNode.Child[1].Val
4445
cl := mNode.Child[0].Const
4546
cr := mNode.Child[1].Const
4647

47-
f := func(k uint64) error {
48+
f := func(k uint64, lshard, rshard, destMapi *map[uint64]types.Val) error {
4849
ag := aggregator{
4950
name: aggName,
5051
}
51-
lVal := mpl[k]
52+
lVal := (*lshard)[k]
5253
if cl.Value != nil {
5354
// Use the constant value that was supplied.
5455
lVal = cl
5556
}
56-
rVal := mpr[k]
57+
rVal := (*rshard)[k]
5758
if cr.Value != nil {
5859
// Use the constant value that was supplied.
5960
rVal = cr
@@ -66,7 +67,7 @@ func processBinary(mNode *mathTree) error {
6667
if err != nil {
6768
return err
6869
}
69-
destMap[k], err = ag.Value()
70+
(*destMapi)[k], err = ag.Value()
7071
if err != nil {
7172
return err
7273
}
@@ -75,12 +76,12 @@ func processBinary(mNode *mathTree) error {
7576

7677
// If mpl or mpr have 0 and just 0 in it, that means it's an output of aggregation somewhere.
7778
// This value would need to be applied to all.
78-
checkAggrResult := func(value map[uint64]types.Val) (types.Val, bool) {
79-
if len(value) != 1 {
79+
checkAggrResult := func(value *types.ShardedMap) (types.Val, bool) {
80+
if value.Len() != 1 {
8081
return types.Val{}, false
8182
}
8283

83-
val, ok := value[0]
84+
val, ok := value.Get(0)
8485
return val, ok
8586
}
8687

@@ -92,21 +93,31 @@ func processBinary(mNode *mathTree) error {
9293
mpr = nil
9394
}
9495

95-
if len(mpl) != 0 || len(mpr) != 0 {
96-
for k := range mpr {
97-
if err := f(k); err != nil {
98-
return err
99-
}
100-
}
101-
for k := range mpl {
102-
if _, ok := mpr[k]; ok {
103-
continue
104-
}
105-
if err := f(k); err != nil {
106-
return err
107-
}
96+
if mpl.Len() != 0 || mpr.Len() != 0 {
97+
var wg sync.WaitGroup
98+
returnMap := types.NewShardedMap()
99+
100+
for i := range types.NumShards {
101+
wg.Add(1)
102+
mlps := mpl.GetShardOrNil(i)
103+
mprs := mpr.GetShardOrNil(i)
104+
destMapi := returnMap.GetShardOrNil(i)
105+
go func(i int) {
106+
defer wg.Done()
107+
for k := range mlps {
108+
f(k, &mlps, &mprs, &destMapi)
109+
}
110+
for k := range mprs {
111+
if _, ok := mlps[k]; ok {
112+
continue
113+
}
114+
f(k, &mlps, &mprs, &destMapi)
115+
}
116+
}(i)
108117
}
109-
mNode.Val = destMap
118+
119+
wg.Wait()
120+
mNode.Val = returnMap
110121
return nil
111122
}
112123

@@ -132,8 +143,8 @@ func processBinary(mNode *mathTree) error {
132143
// processUnary handles the unary operands like
133144
// u-, log, exp, since, floor, ceil
134145
func processUnary(mNode *mathTree) error {
135-
destMap := make(map[uint64]types.Val)
136146
srcMap := mNode.Child[0].Val
147+
destMap := types.NewShardedMap()
137148
aggName := mNode.Fn
138149
ch := mNode.Child[0]
139150
ag := aggregator{
@@ -149,16 +160,18 @@ func processUnary(mNode *mathTree) error {
149160
return err
150161
}
151162

152-
for k, val := range srcMap {
163+
srcMap.Iterate(func(k uint64, val types.Val) error {
153164
err := ag.ApplyVal(val)
154165
if err != nil {
155166
return err
156167
}
157-
destMap[k], err = ag.Value()
168+
value, err := ag.Value()
158169
if err != nil {
159170
return err
160171
}
161-
}
172+
destMap.Set(k, value)
173+
return nil
174+
})
162175
mNode.Val = destMap
163176
return nil
164177

@@ -168,14 +181,14 @@ func processUnary(mNode *mathTree) error {
168181
// return a boolean value.
169182
// All the inequality operators (<, >, <=, >=, !=, ==)
170183
func processBinaryBoolean(mNode *mathTree) error {
171-
destMap := make(map[uint64]types.Val)
172184
srcMap := mNode.Child[0].Val
185+
destMap := types.NewShardedMap()
173186
aggName := mNode.Fn
174187

175188
ch := mNode.Child[1]
176189
curMap := ch.Val
177-
for k, val := range srcMap {
178-
curVal := curMap[k]
190+
srcMap.Iterate(func(k uint64, val types.Val) error {
191+
curVal, _ := curMap.Get(k)
179192
if ch.Const.Value != nil {
180193
// Use the constant value that was supplied.
181194
curVal = ch.Const
@@ -184,28 +197,29 @@ func processBinaryBoolean(mNode *mathTree) error {
184197
if err != nil {
185198
return errors.Wrapf(err, "Wrong values in comparison function.")
186199
}
187-
destMap[k] = types.Val{
200+
destMap.Set(k, types.Val{
188201
Tid: types.BoolID,
189202
Value: res,
190-
}
191-
}
203+
})
204+
return nil
205+
})
192206
mNode.Val = destMap
193207
return nil
194208
}
195209

196210
// processTernary handles the ternary operand cond()
197211
func processTernary(mNode *mathTree) error {
198-
destMap := make(map[uint64]types.Val)
212+
destMap := types.NewShardedMap()
199213
aggName := mNode.Fn
200214
condMap := mNode.Child[0].Val
201-
if len(condMap) == 0 {
215+
if condMap.IsEmpty() {
202216
return errors.Errorf("Expected a value variable in %v but missing.", aggName)
203217
}
204218
varOne := mNode.Child[1].Val
205219
varTwo := mNode.Child[2].Val
206220
constOne := mNode.Child[1].Const
207221
constTwo := mNode.Child[2].Const
208-
for k, val := range condMap {
222+
condMap.Iterate(func(k uint64, val types.Val) error {
209223
var res types.Val
210224
v, ok := val.Value.(bool)
211225
if !ok {
@@ -216,18 +230,19 @@ func processTernary(mNode *mathTree) error {
216230
if constOne.Value != nil {
217231
res = constOne
218232
} else {
219-
res = varOne[k]
233+
res, _ = varOne.Get(k)
220234
}
221235
} else {
222236
// Pick the value of second map.
223237
if constTwo.Value != nil {
224238
res = constTwo
225239
} else {
226-
res = varTwo[k]
240+
res, _ = varTwo.Get(k)
227241
}
228242
}
229-
destMap[k] = res
230-
}
243+
destMap.Set(k, res)
244+
return nil
245+
})
231246
mNode.Val = destMap
232247
return nil
233248
}
@@ -237,7 +252,7 @@ func evalMathTree(mNode *mathTree) error {
237252
return nil
238253
}
239254
if mNode.Var != "" {
240-
if len(mNode.Val) == 0 {
255+
if mNode.Val.IsEmpty() {
241256
glog.V(2).Infof("Variable %v not yet populated or missing.", mNode.Var)
242257
}
243258
// This is a leaf node whose value is already populated. So return.
@@ -246,13 +261,13 @@ func evalMathTree(mNode *mathTree) error {
246261

247262
for _, child := range mNode.Child {
248263
// Process the child nodes first.
249-
err := evalMathTree(child)
250-
if err != nil {
264+
if err := evalMathTree(child); err != nil {
251265
return err
252266
}
253267
}
254268

255269
aggName := mNode.Fn
270+
256271
if isUnary(aggName) {
257272
if len(mNode.Child) != 1 {
258273
return errors.Errorf("Function %v expects 1 argument. But got: %v", aggName,

0 commit comments

Comments
 (0)