github.com/unigraph-dev/dgraph@v1.1.1-0.20200923154953-8b52b426f765/contrib/integration/bigdata/main.go (about)

     1  /*
     2   * Copyright 2018 Dgraph Labs, Inc. and Contributors
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package main
    18  
    19  import (
    20  	"context"
    21  	"encoding/json"
    22  	"flag"
    23  	"fmt"
    24  	"math/rand"
    25  	"net/url"
    26  	"os"
    27  	"strings"
    28  	"sync/atomic"
    29  	"time"
    30  
    31  	"github.com/dgraph-io/dgo"
    32  	"github.com/dgraph-io/dgo/protos/api"
    33  	"github.com/dgraph-io/dgo/x"
    34  	"google.golang.org/grpc"
    35  )
    36  
    37  var addrs = flag.String("addrs", "", "comma separated dgraph addresses")
    38  var mode = flag.String("mode", "", "mode to run in ('mutate' or 'query')")
    39  var conc = flag.Int("j", 1, "number of operations to run in parallel")
    40  
    41  func init() {
    42  	rand.Seed(time.Now().Unix())
    43  }
    44  
    45  var ctx = context.Background()
    46  
    47  func main() {
    48  	flag.Parse()
    49  	c := makeClient()
    50  
    51  	// Install the schema automatically on the first run. This allows the same
    52  	// command to be used when running this program for the first and
    53  	// subsequent times. We guess if it's the first run based on the number of
    54  	// schema items.
    55  	resp, err := c.NewTxn().Query(ctx, "schema {}")
    56  	x.Check(err)
    57  	if len(resp.Json) < 5 {
    58  		// Run each schema alter separately so that there is an even
    59  		// distribution among all groups.
    60  		for _, s := range schema() {
    61  			x.Check(c.Alter(ctx, &api.Operation{
    62  				Schema: s,
    63  			}))
    64  		}
    65  		x.Check2(c.NewTxn().Mutate(ctx, &api.Mutation{
    66  			CommitNow: true,
    67  			SetNquads: []byte(initialData()),
    68  		}))
    69  	}
    70  
    71  	switch *mode {
    72  	case "mutate":
    73  		var errCount int64
    74  		var mutateCount int64
    75  		for i := 0; i < *conc; i++ {
    76  			go func() {
    77  				for {
    78  					err := mutate(c)
    79  					if err == nil {
    80  						atomic.AddInt64(&mutateCount, 1)
    81  					} else {
    82  						atomic.AddInt64(&errCount, 1)
    83  					}
    84  				}
    85  			}()
    86  		}
    87  		for {
    88  			time.Sleep(time.Second)
    89  			fmt.Printf("Status: success_mutations=%d errors=%d\n",
    90  				atomic.LoadInt64(&mutateCount), atomic.LoadInt64(&errCount))
    91  		}
    92  	case "query":
    93  		var errCount int64
    94  		var queryCount int64
    95  		for i := 0; i < *conc; i++ {
    96  			go func() {
    97  				for {
    98  					err := showNode(c)
    99  					if err == nil {
   100  						atomic.AddInt64(&queryCount, 1)
   101  					} else {
   102  						atomic.AddInt64(&errCount, 1)
   103  					}
   104  				}
   105  			}()
   106  		}
   107  		for {
   108  			time.Sleep(time.Second)
   109  			fmt.Printf("Status: success_queries=%d errors=%d\n",
   110  				atomic.LoadInt64(&queryCount), atomic.LoadInt64(&errCount))
   111  		}
   112  	default:
   113  		fmt.Printf("unknown mode: %q\n", *mode)
   114  		os.Exit(1)
   115  	}
   116  }
   117  
   118  func schema() []string {
   119  	s := []string{"xid: string @index(exact) .\n"}
   120  	for char := 'a'; char <= 'z'; char++ {
   121  		s = append(s, fmt.Sprintf("count_%c: int .\n", char))
   122  	}
   123  	for char := 'a'; char <= 'z'; char++ {
   124  		s = append(s, fmt.Sprintf("attr_%c: string .\n", char))
   125  	}
   126  	return s
   127  }
   128  
   129  func initialData() string {
   130  	rdfs := "_:root <xid> \"root\" .\n"
   131  	for char := 'a'; char <= 'z'; char++ {
   132  		rdfs += fmt.Sprintf("_:root <count_%c> \"0\" .\n", char)
   133  	}
   134  	return rdfs
   135  }
   136  
   137  func makeClient() *dgo.Dgraph {
   138  	var dgcs []api.DgraphClient
   139  	for _, addr := range strings.Split(*addrs, ",") {
   140  		c, err := grpc.Dial(addr, grpc.WithInsecure())
   141  		x.Check(err)
   142  		dgcs = append(dgcs, api.NewDgraphClient(c))
   143  	}
   144  	return dgo.NewDgraphClient(dgcs...)
   145  }
   146  
   147  type runner struct {
   148  	txn *dgo.Txn
   149  }
   150  
   151  func mutate(c *dgo.Dgraph) error {
   152  	r := &runner{
   153  		txn: c.NewTxn(),
   154  	}
   155  	defer func() { _ = r.txn.Discard(ctx) }()
   156  
   157  	char := 'a' + rune(rand.Intn(26))
   158  
   159  	var result struct {
   160  		Q []struct {
   161  			Uid   *string
   162  			Count *int
   163  		}
   164  	}
   165  	if err := r.query(&result, `
   166  	{
   167  		q(func: eq(xid, "root")) {
   168  			uid
   169  			count: count_%c
   170  		}
   171  	}
   172  	`, char); err != nil {
   173  		return err
   174  	}
   175  
   176  	x.AssertTrue(len(result.Q) > 0 && result.Q[0].Count != nil && result.Q[0].Uid != nil)
   177  
   178  	if _, err := r.txn.Mutate(ctx, &api.Mutation{
   179  		SetNquads: []byte(fmt.Sprintf("<%s> <count_%c> \"%d\" .\n",
   180  			*result.Q[0].Uid, char, *result.Q[0].Count+1)),
   181  	}); err != nil {
   182  		return err
   183  	}
   184  
   185  	rdfs := fmt.Sprintf("_:node <xid> \"%c_%d\" .\n", char, *result.Q[0].Count)
   186  	for char := 'a'; char <= 'z'; char++ {
   187  		if rand.Float64() < 0.9 {
   188  			continue
   189  		}
   190  		payload := make([]byte, 16+rand.Intn(16))
   191  		rand.Read(payload)
   192  		rdfs += fmt.Sprintf("_:node <attr_%c> \"%s\" .\n", char, url.QueryEscape(string(payload)))
   193  	}
   194  	if _, err := r.txn.Mutate(ctx, &api.Mutation{
   195  		SetNquads: []byte(rdfs),
   196  	}); err != nil {
   197  		return err
   198  	}
   199  
   200  	return r.txn.Commit(ctx)
   201  }
   202  
   203  func showNode(c *dgo.Dgraph) error {
   204  	r := &runner{
   205  		txn: c.NewTxn(),
   206  	}
   207  	defer func() { _ = r.txn.Discard(ctx) }()
   208  
   209  	char := 'a' + rune(rand.Intn(26))
   210  	var result struct {
   211  		Q []struct {
   212  			Count *int
   213  		}
   214  	}
   215  
   216  	q := fmt.Sprintf(`
   217  	{
   218  		q(func: eq(xid, "root")) {
   219  			uid
   220  			count: count_%c
   221  		}
   222  	}
   223  	`, char)
   224  	resp, err := r.txn.Query(ctx, q)
   225  	if err != nil {
   226  		return err
   227  	}
   228  	if err := json.Unmarshal(resp.Json, &result); err != nil {
   229  		return err
   230  	}
   231  	x.AssertTruef(len(result.Q) > 0 && result.Q[0].Count != nil, "%v %+v", string(resp.Json), result)
   232  
   233  	var m map[string]interface{}
   234  	return r.query(&m, `
   235  	{
   236  		q(func: eq(xid, "%c_%d")) {
   237  			expand(_all_)
   238  		}
   239  	}
   240  	`, char, rand.Intn(*result.Q[0].Count))
   241  }
   242  
   243  func (r *runner) query(out interface{}, q string, args ...interface{}) error {
   244  	q = fmt.Sprintf(q, args...)
   245  	resp, err := r.txn.Query(ctx, q)
   246  	if err != nil {
   247  		return err
   248  	}
   249  	return json.Unmarshal(resp.Json, out)
   250  }