func update(stm *semantic.Statement, store storage.Store, f updater) error { var ( mu sync.Mutex wg sync.WaitGroup errs []string ) appendError := func(err error) { mu.Lock() defer mu.Unlock() errs = append(errs, err.Error()) } for _, graphBinding := range stm.Graphs() { wg.Add(1) go func(graph string) { defer wg.Done() g, err := store.Graph(graph) if err != nil { appendError(err) return } err = f(g, stm.Data()) if err != nil { appendError(err) } }(graphBinding) } wg.Wait() if len(errs) > 0 { return errors.New(strings.Join(errs, "; ")) } return nil }
// getGraphFromStore returns a Graph. Will create it if it does not exist. func getGraphFromStore(ctx context.Context, st storage.Store, id string) (storage.Graph, error) { g, err := st.Graph(ctx, id) if err == nil { return g, nil } return st.NewGraph(ctx, id) }
// newQueryPlan returns a new query plan ready to be excecuted. func newQueryPlan(store storage.Store, stm *semantic.Statement) (*queryPlan, error) { bs := []string{} for _, b := range stm.Bindings() { bs = append(bs, b) } t, err := table.New([]string{}) if err != nil { return nil, err } var gs []storage.Graph for _, g := range stm.Graphs() { ng, err := store.Graph(g) if err != nil { return nil, err } gs = append(gs, ng) } return &queryPlan{ stm: stm, store: store, bndgs: bs, grfs: gs, grfsNames: stm.Graphs(), cls: stm.SortedGraphPatternClauses(), tbl: t, }, nil }
// BQLRandomGraphWalking creates the benchmark. func BQLRandomGraphWalking(ctx context.Context, st storage.Store, chanSize int) ([]*runtime.BenchEntry, error) { rgSize := []int{1000, 10000} sizes := []int{10, 1000, 100000} var trplSets [][]*triple.Triple var ids []string var gids []string var gSizes []int gs, err := getGraphGenerators(rgSize) if err != nil { return nil, err } for idx, g := range gs { for _, s := range sizes { ts, err := g.Generate(s) if err != nil { return nil, err } trplSets = append(trplSets, ts) ids = append(ids, fmt.Sprintf("bql rg branch_factor=%04d, size=%07d", rgSize[idx], s)) gids = append(gids, fmt.Sprintf("bql_b%d_s%d", rgSize[idx], s)) gSizes = append(gSizes, s) } } var bes []*runtime.BenchEntry reps := []int{10} for bqlIdx, bqlQuery := range treeGraphWalkingBQL { bql := bqlQuery for i, max := 0, len(ids); i < max; i++ { for idxReps, r := range reps { var g storage.Graph gID := fmt.Sprintf("bql_rg_%d_%s_r%d_i%d", bqlIdx, gids[i], i, idxReps) data := trplSets[i] bes = append(bes, &runtime.BenchEntry{ BatteryID: fmt.Sprintf("Run BQL random graph walking query %d", bqlIdx), ID: fmt.Sprintf("%s, reps=%02d", ids[i], r), Triples: gSizes[i], Reps: r, Setup: func() error { var err error g, err = st.NewGraph(ctx, "?"+gID) if err != nil { return err } return g.AddTriples(ctx, data) }, F: func() error { query := fmt.Sprintf(bql, gID) _, err := run.BQL(ctx, query, st, chanSize) return err }, TearDown: func() error { return st.DeleteGraph(ctx, "?"+gID) }, }) } } } return bes, nil }
// cleanSources create all the graph required for the story and // populates it with the provided data. func (s *Story) cleanSources(ctx context.Context, st storage.Store) error { for _, src := range s.Sources { if err := st.DeleteGraph(ctx, src.ID); err != nil { return err } } return nil }
// RemoveExistingTreeTriplesBenchmark creates the benchmark. func RemoveExistingTreeTriplesBenchmark(ctx context.Context, st storage.Store, chanSize int) ([]*runtime.BenchEntry, error) { bFactors := []int{2, 200} sizes := []int{10, 1000, 100000} var trplSets [][]*triple.Triple var ids []string var gids []string var gSizes []int gs, err := getTreeGenerators(bFactors) if err != nil { return nil, err } for idx, g := range gs { for _, s := range sizes { ts, err := g.Generate(s) if err != nil { return nil, err } trplSets = append(trplSets, ts) ids = append(ids, fmt.Sprintf("etg branch_factor=%04d, size=%07d", bFactors[idx], s)) gids = append(gids, fmt.Sprintf("b%d_s%d", bFactors[idx], s)) gSizes = append(gSizes, s) } } var bes []*runtime.BenchEntry reps := []int{10} for i, max := 0, len(ids); i < max; i++ { for idxReps, r := range reps { var g storage.Graph gID := fmt.Sprintf("remove_existing_tree_%s_r%d_i%d", gids[i], i, idxReps) data := trplSets[i] bes = append(bes, &runtime.BenchEntry{ BatteryID: "Remove existing triples", ID: fmt.Sprintf("%s, reps=%02d", ids[i], r), Triples: gSizes[i], Reps: r, Setup: func() error { var err error g, err = st.NewGraph(ctx, gID) if err != nil { return err } return g.AddTriples(ctx, data) }, F: func() error { return g.RemoveTriples(ctx, data) }, TearDown: func() error { return st.DeleteGraph(ctx, gID) }, }) } } return bes, nil }
// Eval loads the triples in the file against as indicated by the command. func Eval(ctx context.Context, usage string, args []string, store storage.Store, bulkSize int) int { if len(args) <= 3 { fmt.Fprintf(os.Stderr, "[ERROR] Missing required file path and/or graph names.\n\n%s", usage) return 2 } graphs, path := strings.Split(args[len(args)-2], ","), args[len(args)-1] f, err := os.Create(path) if err != nil { fmt.Fprintf(os.Stderr, "[ERROR] Failed to open target file %q with error %v.\n\n", path, err) return 2 } defer f.Close() var sgs []storage.Graph for _, gr := range graphs { g, err := store.Graph(ctx, gr) if err != nil { fmt.Fprintf(os.Stderr, "[ERROR] Failed to retrieve graph %q with error %v.\n\n", gr, err) return 2 } sgs = append(sgs, g) } cnt := 0 var errs []error var mu sync.Mutex chn := make(chan *triple.Triple, bulkSize) for _, vg := range sgs { go func(g storage.Graph) { err := g.Triples(ctx, chn) mu.Lock() errs = append(errs, err) mu.Unlock() }(vg) } for t := range chn { if _, err := f.WriteString(t.String() + "\n"); err != nil { fmt.Fprintf(os.Stderr, "[ERROR] Failed to write triple %s to file %q, %v.\n\n", t.String(), path, err) return 2 } cnt++ } for _, err := range errs { if err != nil { fmt.Fprintf(os.Stderr, "[ERROR] Failed to retrieve triples with error %v.\n\n", err) return 2 } } fmt.Printf("Successfully written %d triples to file %q.\nTriples exported from graphs:\n\t- %s\n", cnt, path, strings.Join(graphs, "\n\t- ")) return 0 }
func flush(ctx context.Context, graphs []string, store storage.Store) error { defer func() { workingTrpls = nil }() if len(workingTrpls) > 0 { for _, graph := range graphs { g, err := store.Graph(ctx, graph) if err != nil { return err } if err := g.AddTriples(ctx, workingTrpls); err != nil { return err } } } return nil }
// REPL starts a read-evaluation-print-loop to run BQL commands. func REPL(driver storage.Store, input *os.File, rl ReadLiner, chanSize, bulkSize, builderSize int) int { ctx := context.Background() fmt.Printf("Welcome to BadWolf vCli (%d.%d.%d-%s)\n", version.Major, version.Minor, version.Patch, version.Release) fmt.Printf("Using driver %q. Type quit; to exit\n", driver.Name(ctx)) fmt.Printf("Session started at %v\n\n", time.Now()) defer func() { fmt.Printf("\n\nThanks for all those BQL queries!\n\n") }() fmt.Print(prompt) l := "" for line := range rl(input) { nl := strings.TrimSpace(line) if nl == "" { fmt.Print(prompt) continue } if l != "" { l = l + " " + nl } else { l = nl } if !strings.HasSuffix(nl, ";") { // Not done with the statement. continue } if strings.HasPrefix(l, "quit") { break } if strings.HasPrefix(l, "help") { printHelp() fmt.Print(prompt) l = "" continue } if strings.HasPrefix(l, "export") { args := strings.Split("bw "+strings.TrimSpace(l[:len(l)-1]), " ") usage := "Wrong syntax\n\n\tload <graph_names_separated_by_commas> <file_path>\n" export.Eval(ctx, usage, args, driver, bulkSize) fmt.Print(prompt) l = "" continue } if strings.HasPrefix(l, "load") { args := strings.Split("bw "+strings.TrimSpace(l[:len(l)-1]), " ") usage := "Wrong syntax\n\n\tload <file_path> <graph_names_separated_by_commas>\n" load.Eval(ctx, usage, args, driver, bulkSize, builderSize) fmt.Print(prompt) l = "" continue } if strings.HasPrefix(l, "run") { path, cmds, err := runBQLFromFile(ctx, driver, chanSize, strings.TrimSpace(l[:len(l)-1])) if err != nil { fmt.Printf("[ERROR] %s\n\n", err) } else { fmt.Printf("Loaded %q and run %d BQL commands successfully\n\n", path, cmds) } fmt.Print(prompt) l = "" continue } table, err := runBQL(ctx, l, driver, chanSize) l = "" if err != nil { fmt.Printf("[ERROR] %s\n\n", err) } else { if len(table.Bindings()) > 0 { fmt.Println(table.String()) } fmt.Println("[OK]") } fmt.Print(prompt) } return 0 }