<commit_before>package glib

// #cgo pkg-config: glib-2.0 gobject-2.0
// #include <gio/gio.h>
// #include <glib.h>
// #include <glib-object.h>
// #include "glib.go.h"
import "C"
import "unsafe"

// NotificationPriority is a representation of GLib's GNotificationPriority.
type NotificationPriority int

const (
	NOTIFICATION_PRIORITY_NORMAL NotificationPriority = C.G_NOTIFICATION_PRIORITY_NORMAL
	NOTIFICATION_PRIORITY_LOW    NotificationPriority = C.G_NOTIFICATION_PRIORITY_LOW
	NOTIFICATION_PRIORITY_HIGH   NotificationPriority = C.G_NOTIFICATION_PRIORITY_HIGH
	NOTIFICATION_PRIORITY_URGENT NotificationPriority = C.G_NOTIFICATION_PRIORITY_URGENT
)

// Notification is a representation of GNotification.
type Notification struct {
	*Object
}

// native() returns a pointer to the underlying GNotification.
func (v *Notification) native() *C.GNotification {
	if v == nil || v.GObject == nil {
		return nil
	}
	return C.toGNotification(unsafe.Pointer(v.GObject))
}

func (v *Notification) Native() uintptr {
	return uintptr(unsafe.Pointer(v.native()))
}

func marshalNotification(p uintptr) (interface{}, error) {
	c := C.g_value_get_object((*C.GValue)(unsafe.Pointer(p)))
	return wrapNotification(wrapObject(unsafe.Pointer(c))), nil
}

func wrapNotification(obj *Object) *Notification {
	return &Notification{obj}
}

// NotificationNew is a wrapper around g_notification_new().
func NotificationNew(title string) *Notification {
	cstr1 := (*C.gchar)(C.CString(title))
	defer C.free(unsafe.Pointer(cstr1))

	c := C.g_notification_new(cstr1)
	if c == nil {
		return nil
	}
	return wrapNotification(wrapObject(unsafe.Pointer(c)))
}

// SetTitle is a wrapper around g_notification_set_title().
func (v *Notification) SetTitle(title string) {
	cstr1 := (*C.gchar)(C.CString(title))
	defer C.free(unsafe.Pointer(cstr1))

	C.g_notification_set_title(v.native(), cstr1)
}

// SetBody is a wrapper around g_notification_set_body().
func (v *Notification) SetBody(body string) {
	cstr1 := (*C.gchar)(C.CString(body))
	defer C.free(unsafe.Pointer(cstr1))

	C.g_notification_set_body(v.native(), cstr1)
}

// SetPriority is a wrapper around g_notification_set_priority().
func (v *Notification) SetPriority(prio NotificationPriority) {
	C.g_notification_set_priority(v.native(), C.GNotificationPriority(prio))
}

// SetDefaultAction is a wrapper around g_notification_set_default_action().
func (v *Notification) SetDefaultAction(detailedAction string) {
	cstr1 := (*C.gchar)(C.CString(detailedAction))
	defer C.free(unsafe.Pointer(cstr1))

	C.g_notification_set_default_action(v.native(), cstr1)
}

// AddButton is a wrapper around g_notification_add_button().
func (v *Notification) AddButton(label, detailedAction string) {
	cstr1 := (*C.gchar)(C.CString(label))
	defer C.free(unsafe.Pointer(cstr1))

	cstr2 := (*C.gchar)(C.CString(detailedAction))
	defer C.free(unsafe.Pointer(cstr2))

	C.g_notification_add_button(v.native(), cstr1, cstr2)
}

// void 	g_notification_set_default_action_and_target () // requires varargs
// void 	g_notification_set_default_action_and_target_value () // requires variant
// void 	g_notification_add_button_with_target () // requires varargs
// void 	g_notification_add_button_with_target_value () //requires variant
// void 	g_notification_set_urgent () // Deprecated, so not implemented
// void 	g_notification_set_icon () // Requires support for GIcon, which we don't have yet.
<commit_msg>Remove even more things that aren't available<commit_after>package glib

// #cgo pkg-config: glib-2.0 gobject-2.0
// #include <gio/gio.h>
// #include <glib.h>
// #include <glib-object.h>
// #include "glib.go.h"
import "C"
import "unsafe"

// Only available from 2.42
// // NotificationPriority is a representation of GLib's GNotificationPriority.
// type NotificationPriority int

// const (
// 	NOTIFICATION_PRIORITY_NORMAL NotificationPriority = C.G_NOTIFICATION_PRIORITY_NORMAL
// 	NOTIFICATION_PRIORITY_LOW    NotificationPriority = C.G_NOTIFICATION_PRIORITY_LOW
// 	NOTIFICATION_PRIORITY_HIGH   NotificationPriority = C.G_NOTIFICATION_PRIORITY_HIGH
// 	NOTIFICATION_PRIORITY_URGENT NotificationPriority = C.G_NOTIFICATION_PRIORITY_URGENT
// )

// Notification is a representation of GNotification.
type Notification struct {
	*Object
}

// native() returns a pointer to the underlying GNotification.
func (v *Notification) native() *C.GNotification {
	if v == nil || v.GObject == nil {
		return nil
	}
	return C.toGNotification(unsafe.Pointer(v.GObject))
}

func (v *Notification) Native() uintptr {
	return uintptr(unsafe.Pointer(v.native()))
}

func marshalNotification(p uintptr) (interface{}, error) {
	c := C.g_value_get_object((*C.GValue)(unsafe.Pointer(p)))
	return wrapNotification(wrapObject(unsafe.Pointer(c))), nil
}

func wrapNotification(obj *Object) *Notification {
	return &Notification{obj}
}

// NotificationNew is a wrapper around g_notification_new().
func NotificationNew(title string) *Notification {
	cstr1 := (*C.gchar)(C.CString(title))
	defer C.free(unsafe.Pointer(cstr1))

	c := C.g_notification_new(cstr1)
	if c == nil {
		return nil
	}
	return wrapNotification(wrapObject(unsafe.Pointer(c)))
}

// SetTitle is a wrapper around g_notification_set_title().
func (v *Notification) SetTitle(title string) {
	cstr1 := (*C.gchar)(C.CString(title))
	defer C.free(unsafe.Pointer(cstr1))

	C.g_notification_set_title(v.native(), cstr1)
}

// SetBody is a wrapper around g_notification_set_body().
func (v *Notification) SetBody(body string) {
	cstr1 := (*C.gchar)(C.CString(body))
	defer C.free(unsafe.Pointer(cstr1))

	C.g_notification_set_body(v.native(), cstr1)
}

// Only available from 2.42
// // SetPriority is a wrapper around g_notification_set_priority().
// func (v *Notification) SetPriority(prio NotificationPriority) {
// 	C.g_notification_set_priority(v.native(), C.GNotificationPriority(prio))
// }

// SetDefaultAction is a wrapper around g_notification_set_default_action().
func (v *Notification) SetDefaultAction(detailedAction string) {
	cstr1 := (*C.gchar)(C.CString(detailedAction))
	defer C.free(unsafe.Pointer(cstr1))

	C.g_notification_set_default_action(v.native(), cstr1)
}

// AddButton is a wrapper around g_notification_add_button().
func (v *Notification) AddButton(label, detailedAction string) {
	cstr1 := (*C.gchar)(C.CString(label))
	defer C.free(unsafe.Pointer(cstr1))

	cstr2 := (*C.gchar)(C.CString(detailedAction))
	defer C.free(unsafe.Pointer(cstr2))

	C.g_notification_add_button(v.native(), cstr1, cstr2)
}

// void 	g_notification_set_default_action_and_target () // requires varargs
// void 	g_notification_set_default_action_and_target_value () // requires variant
// void 	g_notification_add_button_with_target () // requires varargs
// void 	g_notification_add_button_with_target_value () //requires variant
// void 	g_notification_set_urgent () // Deprecated, so not implemented
// void 	g_notification_set_icon () // Requires support for GIcon, which we don't have yet.
<|endoftext|>


<commit_before>package matchmaking

import "github.com/fly/config"

// Config describes the config object..
type Config struct {
	TeamPlayerCount int      `yaml:"team_player_count"`
	TeamCount       int      `yaml:"teams"`
	Checks          []string `yaml:"checks"`
}

// NewConfig reads configuration from environment and returns a config object.
func NewConfig() (c *config.Config, err error) {
	c, err = config.NewConfigFromNamespace("fly", "matchmaking")
	return
}
<commit_msg>errcheck<commit_after>package matchmaking

import "github.com/fly/config"

// Config describes the config object..
type Config struct {
	TeamPlayerCount int      `yaml:"team_player_count"`
	TeamCount       int      `yaml:"teams"`
	Checks          []string `yaml:"checks"`
}

// NewConfig reads configuration from environment and returns a config object.
func NewConfig() (c *config.Config, err error) {
	c, err = config.NewConfigFromNamespace("fly", "matchmaking")
	if err != nil {
		return
	}
	return
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

var (
	flagOut  = flag.String("o", "", "output file")
	flagFunc = flag.String("func", "Fuzz", "entry function")

	workdir string
)

const (
	mainPkg = "go-fuzz-main"
)

// Copies the package with all dependent packages into a temp dir,
// instruments Go source files there and builds setting GOROOT to the temp dir.
func main() {
	flag.Parse()
	if len(flag.Args()) != 1 {
		failf("usage: go-fuzz-build pkg")
	}
	if os.Getenv("GOROOT") == "" {
		failf("GOROOT env var is not set, set it to Go installation dir")
	}

	pkg := flag.Arg(0)

	// To produce error messages (this is much faster and gives correct line numbers).
	testNormalBuild(pkg)

	deps := make(map[string]bool)
	for _, p := range goListList(pkg, "Deps") {
		deps[p] = true
	}
	deps[pkg] = true
	// These packages are used by go-fuzz-dep, so we need to copy them regardless.
	deps["runtime"] = true
	deps["syscall"] = true
	deps["time"] = true
	deps["unsafe"] = true

	if *flagOut == "" {
		*flagOut = goListProps(pkg, "Name")[0] + "-fuzz"
	}

	var err error
	workdir, err = ioutil.TempDir("", "go-fuzz-build")
	if err != nil {
		failf("failed to create temp dir: %v", err)
	}
	defer os.RemoveAll(workdir)

	if deps["runtime/cgo"] {
		// Trick go command into thinking that it has up-to-date sources for cmd/cgo.
		cgoDir := filepath.Join(workdir, "src", "cmd", "cgo")
		if err := os.MkdirAll(cgoDir, 0700); err != nil {
			failf("failed to create temp dir: %v", err)
		}
		src := "// +build never\npackage main\n"
		if err := ioutil.WriteFile(filepath.Join(cgoDir, "fake.go"), []byte(src), 0600); err != nil {
			failf("failed to write temp file: %v", err)
		}
	}
	copyDir(filepath.Join(os.Getenv("GOROOT"), "pkg", "tool"), filepath.Join(workdir, "pkg", "tool"), false, true)
	copyDir(filepath.Join(os.Getenv("GOROOT"), "pkg", "include"), filepath.Join(workdir, "pkg", "include"), false, true)
	for p := range deps {
		clonePackage(workdir, p)
	}
	createFuzzMain(pkg)

	cmd := exec.Command("go", "build", "-tags", "gofuzz", "-o", *flagOut, mainPkg)
	for _, v := range os.Environ() {
		if strings.HasPrefix(v, "GOROOT") {
			continue
		}
		cmd.Env = append(cmd.Env, v)
	}
	cmd.Env = append(cmd.Env, "GOROOT="+workdir)
	if out, err := cmd.CombinedOutput(); err != nil {
		failf("failed to execute go build: %v\n%v", err, string(out))
	}
}

func testNormalBuild(pkg string) {
	var err error
	workdir, err = ioutil.TempDir("", "go-fuzz-build")
	if err != nil {
		failf("failed to create temp dir: %v", err)
	}
	defer func() {
		os.RemoveAll(workdir)
		workdir = ""
	}()
	createFuzzMain(pkg)
	cmd := exec.Command("go", "build", "-tags", "gofuzz", "-o", filepath.Join(workdir, "bin"), mainPkg)
	cmd.Env = append([]string{"GOPATH=" + workdir + ":" + os.Getenv("GOPATH")}, os.Environ()...)
	if out, err := cmd.CombinedOutput(); err != nil {
		failf("failed to execute go build: %v\n%v", err, string(out))
	}
}

func createFuzzMain(pkg string) {
	if err := os.MkdirAll(filepath.Join(workdir, "src", mainPkg), 0700); err != nil {
		failf("failed to create temp dir: %v", err)
	}
	src := fmt.Sprintf(mainSrc, pkg, *flagFunc)
	if err := ioutil.WriteFile(filepath.Join(workdir, "src", mainPkg, "main.go"), []byte(src), 0600); err != nil {
		failf("failed to write temp file: %v", err)
	}
}

func clonePackage(workdir, pkg string) {
	dir := goListProps(pkg, "Dir")[0]
	if !strings.HasSuffix(dir, pkg) {
		failf("package dir '%v' does not end with import path '%v'", dir, pkg)
	}
	newDir := filepath.Join(workdir, "src", pkg)
	copyDir(dir, newDir, true, false)
	ignore := []string{
		"runtime",       // lots of non-determinism and irrelevant code paths (e.g. different paths in mallocgc, chans and maps)
		"unsafe",        // nothing to see here (also creates import cycle with go-fuzz-dep)
		"errors",        // nothing to see here (also creates import cycle with go-fuzz-dep)
		"syscall",       // creates import cycle with go-fuzz-dep (and probably nothing to see here)
		"sync",          // non-deterministic and not interesting (also creates import cycle with go-fuzz-dep)
		"sync/atomic",   // not interesting (also creates import cycle with go-fuzz-dep)
		"time",          // creates import cycle with go-fuzz-dep
		"runtime/cgo",   // why would we instrument it?
		"runtime/pprof", // why would we instrument it?
		"runtime/race",  // why would we instrument it?
	}
	for _, p := range ignore {
		if pkg == p {
			return
		}
	}
	files, err := ioutil.ReadDir(newDir)
	if err != nil {
		failf("failed to scan dir '%v': %v", dir, err)
	}
	for _, f := range files {
		if f.IsDir() {
			continue
		}
		if !strings.HasSuffix(f.Name(), ".go") {
			continue
		}
		fn := filepath.Join(newDir, f.Name())
		newFn := fn + ".cover"
		instrument(fn, newFn)
		err := os.Rename(newFn, fn)
		if err != nil {
			failf("failed to rename file: %v", err)
		}
	}
}

func copyDir(dir, newDir string, src, rec bool) {
	if err := os.MkdirAll(newDir, 0700); err != nil {
		failf("failed to create temp dir: %v", err)
	}
	files, err := ioutil.ReadDir(dir)
	if err != nil {
		failf("failed to scan dir '%v': %v", dir, err)
	}
	for _, f := range files {
		if f.IsDir() {
			if rec {
				copyDir(filepath.Join(dir, f.Name()), filepath.Join(newDir, f.Name()), src, rec)
			}
			continue
		}
		if src && !isSourceFile(f.Name()) {
			continue
		}
		data, err := ioutil.ReadFile(filepath.Join(dir, f.Name()))
		if err != nil {
			failf("failed to read file: %v", err)
		}
		if err := ioutil.WriteFile(filepath.Join(newDir, f.Name()), data, 0700); err != nil {
			failf("failed to write temp file: %v", err)
		}
	}
}

func goListList(pkg, what string) []string {
	templ := fmt.Sprintf("{{range .%v}}{{.}}|{{end}}", what)
	out, err := exec.Command("go", "list", "-tags", "gofuzz", "-f", templ, pkg).CombinedOutput()
	if err != nil {
		failf("failed to execute 'go list -f \"%v\" %v': %v\n%v", templ, pkg, err, string(out))
	}
	if len(out) < 2 {
		failf("go list output is empty")
	}
	out = out[:len(out)-2]
	return strings.Split(string(out), "|")
}

func goListProps(pkg string, props ...string) []string {
	templ := ""
	for _, p := range props {
		templ += fmt.Sprintf("{{.%v}}|", p)
	}
	out, err := exec.Command("go", "list", "-tags", "gofuzz", "-f", templ, pkg).CombinedOutput()
	if err != nil {
		failf("failed to execute 'go list -f \"%v\" %v': %v\n%v", templ, pkg, err, string(out))
	}
	if len(out) == 0 {
		failf("go list output is empty")
	}
	out = out[:len(out)-1]
	return strings.Split(string(out), "|")
}

func failf(str string, args ...interface{}) {
	if workdir != "" {
		os.RemoveAll(workdir)
	}
	fmt.Fprintf(os.Stderr, str+"\n", args...)
	os.Exit(1)
}

func isSourceFile(f string) bool {
	return strings.HasSuffix(f, ".go") ||
		strings.HasSuffix(f, ".s") ||
		strings.HasSuffix(f, ".S") ||
		strings.HasSuffix(f, ".c") ||
		strings.HasSuffix(f, ".h") ||
		strings.HasSuffix(f, ".cxx") ||
		strings.HasSuffix(f, ".cpp") ||
		strings.HasSuffix(f, ".c++") ||
		strings.HasSuffix(f, ".cc")
}

var mainSrc = `
package main

import (
	target "%v"
	dep "github.com/dvyukov/go-fuzz/go-fuzz-dep"
)

func main() {
	dep.Main(target.%v)
}
`
<commit_msg>add diagnostic for relative import paths in go-fuzz-build<commit_after>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

var (
	flagOut  = flag.String("o", "", "output file")
	flagFunc = flag.String("func", "Fuzz", "entry function")

	workdir string
)

const (
	mainPkg = "go-fuzz-main"
)

// Copies the package with all dependent packages into a temp dir,
// instruments Go source files there and builds setting GOROOT to the temp dir.
func main() {
	flag.Parse()
	if len(flag.Args()) != 1 || len(flag.Arg(0)) == 0 {
		failf("usage: go-fuzz-build pkg")
	}
	if os.Getenv("GOROOT") == "" {
		failf("GOROOT env var is not set, set it to Go installation dir")
	}
	pkg := flag.Arg(0)
	if pkg[0] == '.' {
		failf("relative import paths are not supported, please specify full package name")
	}

	// To produce error messages (this is much faster and gives correct line numbers).
	testNormalBuild(pkg)

	deps := make(map[string]bool)
	for _, p := range goListList(pkg, "Deps") {
		deps[p] = true
	}
	deps[pkg] = true
	// These packages are used by go-fuzz-dep, so we need to copy them regardless.
	deps["runtime"] = true
	deps["syscall"] = true
	deps["time"] = true
	deps["unsafe"] = true

	if *flagOut == "" {
		*flagOut = goListProps(pkg, "Name")[0] + "-fuzz"
	}

	var err error
	workdir, err = ioutil.TempDir("", "go-fuzz-build")
	if err != nil {
		failf("failed to create temp dir: %v", err)
	}
	defer os.RemoveAll(workdir)

	if deps["runtime/cgo"] {
		// Trick go command into thinking that it has up-to-date sources for cmd/cgo.
		cgoDir := filepath.Join(workdir, "src", "cmd", "cgo")
		if err := os.MkdirAll(cgoDir, 0700); err != nil {
			failf("failed to create temp dir: %v", err)
		}
		src := "// +build never\npackage main\n"
		if err := ioutil.WriteFile(filepath.Join(cgoDir, "fake.go"), []byte(src), 0600); err != nil {
			failf("failed to write temp file: %v", err)
		}
	}
	copyDir(filepath.Join(os.Getenv("GOROOT"), "pkg", "tool"), filepath.Join(workdir, "pkg", "tool"), false, true)
	copyDir(filepath.Join(os.Getenv("GOROOT"), "pkg", "include"), filepath.Join(workdir, "pkg", "include"), false, true)
	for p := range deps {
		clonePackage(workdir, p)
	}
	createFuzzMain(pkg)

	cmd := exec.Command("go", "build", "-tags", "gofuzz", "-o", *flagOut, mainPkg)
	for _, v := range os.Environ() {
		if strings.HasPrefix(v, "GOROOT") {
			continue
		}
		cmd.Env = append(cmd.Env, v)
	}
	cmd.Env = append(cmd.Env, "GOROOT="+workdir)
	if out, err := cmd.CombinedOutput(); err != nil {
		failf("failed to execute go build: %v\n%v", err, string(out))
	}
}

func testNormalBuild(pkg string) {
	var err error
	workdir, err = ioutil.TempDir("", "go-fuzz-build")
	if err != nil {
		failf("failed to create temp dir: %v", err)
	}
	defer func() {
		os.RemoveAll(workdir)
		workdir = ""
	}()
	createFuzzMain(pkg)
	cmd := exec.Command("go", "build", "-tags", "gofuzz", "-o", filepath.Join(workdir, "bin"), mainPkg)
	cmd.Env = append([]string{"GOPATH=" + workdir + ":" + os.Getenv("GOPATH")}, os.Environ()...)
	if out, err := cmd.CombinedOutput(); err != nil {
		failf("failed to execute go build: %v\n%v", err, string(out))
	}
}

func createFuzzMain(pkg string) {
	if err := os.MkdirAll(filepath.Join(workdir, "src", mainPkg), 0700); err != nil {
		failf("failed to create temp dir: %v", err)
	}
	src := fmt.Sprintf(mainSrc, pkg, *flagFunc)
	if err := ioutil.WriteFile(filepath.Join(workdir, "src", mainPkg, "main.go"), []byte(src), 0600); err != nil {
		failf("failed to write temp file: %v", err)
	}
}

func clonePackage(workdir, pkg string) {
	dir := goListProps(pkg, "Dir")[0]
	if !strings.HasSuffix(dir, pkg) {
		failf("package dir '%v' does not end with import path '%v'", dir, pkg)
	}
	newDir := filepath.Join(workdir, "src", pkg)
	copyDir(dir, newDir, true, false)
	ignore := []string{
		"runtime",       // lots of non-determinism and irrelevant code paths (e.g. different paths in mallocgc, chans and maps)
		"unsafe",        // nothing to see here (also creates import cycle with go-fuzz-dep)
		"errors",        // nothing to see here (also creates import cycle with go-fuzz-dep)
		"syscall",       // creates import cycle with go-fuzz-dep (and probably nothing to see here)
		"sync",          // non-deterministic and not interesting (also creates import cycle with go-fuzz-dep)
		"sync/atomic",   // not interesting (also creates import cycle with go-fuzz-dep)
		"time",          // creates import cycle with go-fuzz-dep
		"runtime/cgo",   // why would we instrument it?
		"runtime/pprof", // why would we instrument it?
		"runtime/race",  // why would we instrument it?
	}
	for _, p := range ignore {
		if pkg == p {
			return
		}
	}
	files, err := ioutil.ReadDir(newDir)
	if err != nil {
		failf("failed to scan dir '%v': %v", dir, err)
	}
	for _, f := range files {
		if f.IsDir() {
			continue
		}
		if !strings.HasSuffix(f.Name(), ".go") {
			continue
		}
		fn := filepath.Join(newDir, f.Name())
		newFn := fn + ".cover"
		instrument(fn, newFn)
		err := os.Rename(newFn, fn)
		if err != nil {
			failf("failed to rename file: %v", err)
		}
	}
}

func copyDir(dir, newDir string, src, rec bool) {
	if err := os.MkdirAll(newDir, 0700); err != nil {
		failf("failed to create temp dir: %v", err)
	}
	files, err := ioutil.ReadDir(dir)
	if err != nil {
		failf("failed to scan dir '%v': %v", dir, err)
	}
	for _, f := range files {
		if f.IsDir() {
			if rec {
				copyDir(filepath.Join(dir, f.Name()), filepath.Join(newDir, f.Name()), src, rec)
			}
			continue
		}
		if src && !isSourceFile(f.Name()) {
			continue
		}
		data, err := ioutil.ReadFile(filepath.Join(dir, f.Name()))
		if err != nil {
			failf("failed to read file: %v", err)
		}
		if err := ioutil.WriteFile(filepath.Join(newDir, f.Name()), data, 0700); err != nil {
			failf("failed to write temp file: %v", err)
		}
	}
}

func goListList(pkg, what string) []string {
	templ := fmt.Sprintf("{{range .%v}}{{.}}|{{end}}", what)
	out, err := exec.Command("go", "list", "-tags", "gofuzz", "-f", templ, pkg).CombinedOutput()
	if err != nil {
		failf("failed to execute 'go list -f \"%v\" %v': %v\n%v", templ, pkg, err, string(out))
	}
	if len(out) < 2 {
		failf("go list output is empty")
	}
	out = out[:len(out)-2]
	return strings.Split(string(out), "|")
}

func goListProps(pkg string, props ...string) []string {
	templ := ""
	for _, p := range props {
		templ += fmt.Sprintf("{{.%v}}|", p)
	}
	out, err := exec.Command("go", "list", "-tags", "gofuzz", "-f", templ, pkg).CombinedOutput()
	if err != nil {
		failf("failed to execute 'go list -f \"%v\" %v': %v\n%v", templ, pkg, err, string(out))
	}
	if len(out) == 0 {
		failf("go list output is empty")
	}
	out = out[:len(out)-1]
	return strings.Split(string(out), "|")
}

func failf(str string, args ...interface{}) {
	if workdir != "" {
		os.RemoveAll(workdir)
	}
	fmt.Fprintf(os.Stderr, str+"\n", args...)
	os.Exit(1)
}

func isSourceFile(f string) bool {
	return strings.HasSuffix(f, ".go") ||
		strings.HasSuffix(f, ".s") ||
		strings.HasSuffix(f, ".S") ||
		strings.HasSuffix(f, ".c") ||
		strings.HasSuffix(f, ".h") ||
		strings.HasSuffix(f, ".cxx") ||
		strings.HasSuffix(f, ".cpp") ||
		strings.HasSuffix(f, ".c++") ||
		strings.HasSuffix(f, ".cc")
}

var mainSrc = `
package main

import (
	target "%v"
	dep "github.com/dvyukov/go-fuzz/go-fuzz-dep"
)

func main() {
	dep.Main(target.%v)
}
`
<|endoftext|>


<commit_before>package posix

import (
	"os"
	"strings"
	"syscall"

	co "github.com/lunixbochs/usercorn/go/kernel/common"
)

func (k *PosixKernel) Read(fd co.Fd, buf co.Obuf, size co.Len) uint64 {
	tmp := make([]byte, size)
	n, err := syscall.Read(int(fd), tmp)
	if err != nil {
		return Errno(err)
	}
	if err := buf.Pack(tmp[:n]); err != nil {
		return UINT64_MAX // FIXME
	}
	return uint64(n)
}

func (k *PosixKernel) Write(fd co.Fd, buf co.Buf, size co.Len) uint64 {
	tmp := make([]byte, size)
	if err := buf.Unpack(tmp); err != nil {
		return UINT64_MAX // FIXME
	}
	n, err := syscall.Write(int(fd), tmp)
	if err != nil {
		return Errno(err)
	}
	return uint64(n)
}

func (k *PosixKernel) Open(path string, mode int, flags uint32) uint64 {
	if strings.Contains(path, "/lib/") {
		path = k.U.PrefixPath(path, false)
	}
	fd, err := syscall.Open(path, mode, flags)
	if err != nil {
		return Errno(err)
	}
	return uint64(fd)
}

func (k *PosixKernel) Close(fd co.Fd) uint64 {
	// FIXME: temporary hack to preserve output on program exit
	if fd == 2 {
		return 0
	}
	return Errno(syscall.Close(int(fd)))
}

func (k *PosixKernel) Lseek(fd co.Fd, offset co.Off, whence int) uint64 {
	off, err := syscall.Seek(int(fd), int64(offset), whence)
	if err != nil {
		return Errno(err)
	}
	return uint64(off)
}

func (k *PosixKernel) Fstat(fd co.Fd, buf co.Buf) uint64 {
	var stat syscall.Stat_t
	if err := syscall.Fstat(int(fd), &stat); err != nil {
		return Errno(err)
	}
	targetStat := NewTargetStat(&stat, k.U.OS(), k.U.Bits())
	if err := buf.Pack(targetStat); err != nil {
		panic(err)
	}
	return 0
}

func (k *PosixKernel) Lstat(path string, buf co.Buf) uint64 {
	var stat syscall.Stat_t
	if err := syscall.Lstat(path, &stat); err != nil {
		return Errno(err)
	}
	targetStat := NewTargetStat(&stat, k.U.OS(), k.U.Bits())
	if err := buf.Pack(targetStat); err != nil {
		panic(err)
	}
	return 0
}

func (k *PosixKernel) Stat(path string, buf co.Buf) uint64 {
	// TODO: centralize path hook
	if strings.Contains(path, "/lib/") {
		path = k.U.PrefixPath(path, false)
	}
	var stat syscall.Stat_t
	if err := syscall.Stat(path, &stat); err != nil {
		return Errno(err)
	}
	targetStat := NewTargetStat(&stat, k.U.OS(), k.U.Bits())
	if err := buf.Pack(targetStat); err != nil {
		panic(err)
	}
	return 0
}

func (k *PosixKernel) Getcwd(buf co.Buf, size co.Len) uint64 {
	wd, _ := os.Getwd()
	size -= 1
	if co.Len(len(wd)) > size {
		wd = wd[:size]
	}
	if err := buf.Pack(wd + "\x00"); err != nil {
		return UINT64_MAX // FIXME
	}
	return 0
}

func (k *PosixKernel) Access(path string, amode uint32) uint64 {
	// TODO: portability
	return Errno(syscall.Access(path, amode))
}

func (k *PosixKernel) Readv(fd co.Fd, iov co.Buf, count uint64) uint64 {
	var read uint64
	for vec := range iovecIter(iov, count, k.U.Bits()) {
		tmp := make([]byte, vec.Len)
		n, err := syscall.Read(int(fd), tmp)
		if err != nil {
			return Errno(err)
		}
		read += uint64(n)
		k.U.MemWrite(vec.Base, tmp[:n])
	}
	return read
}

func (k *PosixKernel) Writev(fd co.Fd, iov co.Buf, count uint64) uint64 {
	var written uint64
	for vec := range iovecIter(iov, count, k.U.Bits()) {
		data, _ := k.U.MemRead(vec.Base, vec.Len)
		n, err := syscall.Write(int(fd), data)
		if err != nil {
			return Errno(err)
		}
		written += uint64(n)
	}
	return written
}

func (k *PosixKernel) Chmod(path string, mode uint32) uint64 {
	return Errno(syscall.Chmod(path, mode))
}

func (k *PosixKernel) Fchmod(fd int, mode uint32) uint64 {
	return Errno(syscall.Fchmod(fd, mode))
}

func (k *PosixKernel) Chown(path string, uid, gid int) uint64 {
	return Errno(syscall.Chown(path, uid, gid))
}

func (k *PosixKernel) Fchown(fd, uid, gid int) uint64 {
	return Errno(syscall.Fchown(fd, uid, gid))
}

func (k *PosixKernel) Lchown(path string, uid, gid int) uint64 {
	return Errno(syscall.Lchown(path, uid, gid))
}

func (k *PosixKernel) Dup(oldFd co.Fd) uint64 {
	if newFd, err := syscall.Dup(int(oldFd)); err != nil {
		return Errno(err)
	} else {
		return uint64(newFd)
	}
}

func (k *PosixKernel) Dup2(oldFd co.Fd, newFd co.Fd) uint64 {
	if err := syscall.Dup2(int(oldFd), int(newFd)); err != nil {
		return Errno(err)
	}
	return uint64(newFd)
}

func (k *PosixKernel) Readlink(path string, buf co.Buf, size co.Len) uint64 {
	// TODO: full proc emulation layer
	// maybe have a syscall pre-hook for this after ghostrace makes it generic
	// or specifically have path hooks and use that to implement prefix as well
	var name string
	var err error
	if path == "/proc/self/exe" && k.U.OS() == "linux" {
		name = k.U.Exe()
	} else {
		name, err = os.Readlink(path)
		if err != nil {
			return UINT64_MAX // FIXME
		}
	}
	if len(name) > int(size)-1 {
		name = name[:size-1]
	}
	if err := buf.Pack([]byte(name + "\x00")); err != nil {
		return UINT64_MAX // FIXME
	}
	return uint64(len(name))
}

func (k *PosixKernel) Symlink(src, dst string) uint64 {
	return Errno(syscall.Symlink(src, dst))
}

func (k *PosixKernel) Link(src, dst string) uint64 {
	return Errno(syscall.Link(src, dst))
}

func (k *PosixKernel) Openat(dirfd co.Fd, path string, flags int, mode uint32) uint64 {
	// TODO: flags might be different per arch
	return openat_native(int(dirfd), path, flags, mode)
}

func (k *PosixKernel) Chdir(path string) uint64 {
	if err := os.Chdir(path); err != nil {
		return UINT64_MAX // FIXME
	}
	return 0
}

func (k *PosixKernel) Chroot(path string) uint64 {
	return Errno(syscall.Chroot(path))
}

func (k *PosixKernel) Pipe(files co.Buf) uint64 {
	var fds [2]int
	err := syscall.Pipe(fds[:])
	if err == nil {
		if err := files.Pack(fds); err != nil {
			return UINT64_MAX // FIXME
		}
	}
	return Errno(err)
}
<commit_msg>add pread and pwrite<commit_after>package posix

import (
	"os"
	"strings"
	"syscall"

	co "github.com/lunixbochs/usercorn/go/kernel/common"
)

func (k *PosixKernel) Read(fd co.Fd, buf co.Obuf, size co.Len) uint64 {
	tmp := make([]byte, size)
	n, err := syscall.Read(int(fd), tmp)
	if err != nil {
		return Errno(err)
	}
	if err := buf.Pack(tmp[:n]); err != nil {
		return UINT64_MAX // FIXME
	}
	return uint64(n)
}

func (k *PosixKernel) Write(fd co.Fd, buf co.Buf, size co.Len) uint64 {
	tmp := make([]byte, size)
	if err := buf.Unpack(tmp); err != nil {
		return UINT64_MAX // FIXME
	}
	n, err := syscall.Write(int(fd), tmp)
	if err != nil {
		return Errno(err)
	}
	return uint64(n)
}

func (k *PosixKernel) Open(path string, mode int, flags uint32) uint64 {
	if strings.Contains(path, "/lib/") {
		path = k.U.PrefixPath(path, false)
	}
	fd, err := syscall.Open(path, mode, flags)
	if err != nil {
		return Errno(err)
	}
	return uint64(fd)
}

func (k *PosixKernel) Close(fd co.Fd) uint64 {
	// FIXME: temporary hack to preserve output on program exit
	if fd == 2 {
		return 0
	}
	return Errno(syscall.Close(int(fd)))
}

func (k *PosixKernel) Lseek(fd co.Fd, offset co.Off, whence int) uint64 {
	off, err := syscall.Seek(int(fd), int64(offset), whence)
	if err != nil {
		return Errno(err)
	}
	return uint64(off)
}

func (k *PosixKernel) Fstat(fd co.Fd, buf co.Buf) uint64 {
	var stat syscall.Stat_t
	if err := syscall.Fstat(int(fd), &stat); err != nil {
		return Errno(err)
	}
	targetStat := NewTargetStat(&stat, k.U.OS(), k.U.Bits())
	if err := buf.Pack(targetStat); err != nil {
		panic(err)
	}
	return 0
}

func (k *PosixKernel) Lstat(path string, buf co.Buf) uint64 {
	var stat syscall.Stat_t
	if err := syscall.Lstat(path, &stat); err != nil {
		return Errno(err)
	}
	targetStat := NewTargetStat(&stat, k.U.OS(), k.U.Bits())
	if err := buf.Pack(targetStat); err != nil {
		panic(err)
	}
	return 0
}

func (k *PosixKernel) Stat(path string, buf co.Buf) uint64 {
	// TODO: centralize path hook
	if strings.Contains(path, "/lib/") {
		path = k.U.PrefixPath(path, false)
	}
	var stat syscall.Stat_t
	if err := syscall.Stat(path, &stat); err != nil {
		return Errno(err)
	}
	targetStat := NewTargetStat(&stat, k.U.OS(), k.U.Bits())
	if err := buf.Pack(targetStat); err != nil {
		panic(err)
	}
	return 0
}

func (k *PosixKernel) Getcwd(buf co.Buf, size co.Len) uint64 {
	wd, _ := os.Getwd()
	size -= 1
	if co.Len(len(wd)) > size {
		wd = wd[:size]
	}
	if err := buf.Pack(wd + "\x00"); err != nil {
		return UINT64_MAX // FIXME
	}
	return 0
}

func (k *PosixKernel) Access(path string, amode uint32) uint64 {
	// TODO: portability
	return Errno(syscall.Access(path, amode))
}

func (k *PosixKernel) Readv(fd co.Fd, iov co.Buf, count uint64) uint64 {
	var read uint64
	for vec := range iovecIter(iov, count, k.U.Bits()) {
		tmp := make([]byte, vec.Len)
		n, err := syscall.Read(int(fd), tmp)
		if err != nil {
			return Errno(err)
		}
		read += uint64(n)
		k.U.MemWrite(vec.Base, tmp[:n])
	}
	return read
}

func (k *PosixKernel) Writev(fd co.Fd, iov co.Buf, count uint64) uint64 {
	var written uint64
	for vec := range iovecIter(iov, count, k.U.Bits()) {
		data, _ := k.U.MemRead(vec.Base, vec.Len)
		n, err := syscall.Write(int(fd), data)
		if err != nil {
			return Errno(err)
		}
		written += uint64(n)
	}
	return written
}

func (k *PosixKernel) Pread(fd co.Fd, buf co.Obuf, size co.Len, offset int64) uint64 {
	p := make([]byte, size)
	n, err := syscall.Pread(int(fd), p, offset)
	if err != nil {
		return Errno(err)
	}
	if err := buf.Pack(p); err != nil {
		return UINT64_MAX // FIXME
	}
	return uint64(n)
}

func (k *PosixKernel) Pwrite(fd co.Fd, buf co.Buf, size co.Len, offset int64) uint64 {
	p := make([]byte, size)
	if err := buf.Unpack(p); err != nil {
		return UINT64_MAX // FIXME
	}
	n, err := syscall.Pwrite(int(fd), p, offset)
	if err != nil {
		return Errno(err)
	}
	return uint64(n)
}

func (k *PosixKernel) Chmod(path string, mode uint32) uint64 {
	return Errno(syscall.Chmod(path, mode))
}

func (k *PosixKernel) Fchmod(fd int, mode uint32) uint64 {
	return Errno(syscall.Fchmod(fd, mode))
}

func (k *PosixKernel) Chown(path string, uid, gid int) uint64 {
	return Errno(syscall.Chown(path, uid, gid))
}

func (k *PosixKernel) Fchown(fd, uid, gid int) uint64 {
	return Errno(syscall.Fchown(fd, uid, gid))
}

func (k *PosixKernel) Lchown(path string, uid, gid int) uint64 {
	return Errno(syscall.Lchown(path, uid, gid))
}

func (k *PosixKernel) Dup(oldFd co.Fd) uint64 {
	if newFd, err := syscall.Dup(int(oldFd)); err != nil {
		return Errno(err)
	} else {
		return uint64(newFd)
	}
}

func (k *PosixKernel) Dup2(oldFd co.Fd, newFd co.Fd) uint64 {
	if err := syscall.Dup2(int(oldFd), int(newFd)); err != nil {
		return Errno(err)
	}
	return uint64(newFd)
}

func (k *PosixKernel) Readlink(path string, buf co.Buf, size co.Len) uint64 {
	// TODO: full proc emulation layer
	// maybe have a syscall pre-hook for this after ghostrace makes it generic
	// or specifically have path hooks and use that to implement prefix as well
	var name string
	var err error
	if path == "/proc/self/exe" && k.U.OS() == "linux" {
		name = k.U.Exe()
	} else {
		name, err = os.Readlink(path)
		if err != nil {
			return UINT64_MAX // FIXME
		}
	}
	if len(name) > int(size)-1 {
		name = name[:size-1]
	}
	if err := buf.Pack([]byte(name + "\x00")); err != nil {
		return UINT64_MAX // FIXME
	}
	return uint64(len(name))
}

func (k *PosixKernel) Symlink(src, dst string) uint64 {
	return Errno(syscall.Symlink(src, dst))
}

func (k *PosixKernel) Link(src, dst string) uint64 {
	return Errno(syscall.Link(src, dst))
}

func (k *PosixKernel) Openat(dirfd co.Fd, path string, flags int, mode uint32) uint64 {
	// TODO: flags might be different per arch
	return openat_native(int(dirfd), path, flags, mode)
}

func (k *PosixKernel) Chdir(path string) uint64 {
	if err := os.Chdir(path); err != nil {
		return UINT64_MAX // FIXME
	}
	return 0
}

func (k *PosixKernel) Chroot(path string) uint64 {
	return Errno(syscall.Chroot(path))
}

func (k *PosixKernel) Pipe(files co.Buf) uint64 {
	var fds [2]int
	err := syscall.Pipe(fds[:])
	if err == nil {
		if err := files.Pack(fds); err != nil {
			return UINT64_MAX // FIXME
		}
	}
	return Errno(err)
}
<|endoftext|>


<commit_before>// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////

package mac

import (
	"fmt"

	"flag"
	"github.com/google/tink/go/core/cryptofmt"
	"github.com/google/tink/go/core/primitiveset"
	"github.com/google/tink/go/core/registry"
	"github.com/google/tink/go/keyset"
	"github.com/google/tink/go/tink"
	tinkpb "github.com/google/tink/go/proto/tink_go_proto"
)

// TODO(b/168188126) Remove once this bug is fixed.
var enableComputeOldLegacyMac = flag.Bool(
	"enable_compute_old_legacy_mac", false,
	"This flag has no effect anymore.")

// New creates a MAC primitive from the given keyset handle.
func New(h *keyset.Handle) (tink.MAC, error) {
	return NewWithKeyManager(h, nil /*keyManager*/)
}

// NewWithKeyManager creates a MAC primitive from the given keyset handle and a custom key manager.
// Deprecated: register the KeyManager and use New above.
func NewWithKeyManager(h *keyset.Handle, km registry.KeyManager) (tink.MAC, error) {
	ps, err := h.PrimitivesWithKeyManager(km)
	if err != nil {
		return nil, fmt.Errorf("mac_factory: cannot obtain primitive set: %s", err)
	}

	return newWrappedMAC(ps)
}

// wrappedMAC is a MAC implementation that uses the underlying primitive set to compute and
// verify MACs.
type wrappedMAC struct {
	ps *primitiveset.PrimitiveSet
}

func newWrappedMAC(ps *primitiveset.PrimitiveSet) (*wrappedMAC, error) {
	if _, ok := (ps.Primary.Primitive).(tink.MAC); !ok {
		return nil, fmt.Errorf("mac_factory: not a MAC primitive")
	}

	for _, primitives := range ps.Entries {
		for _, p := range primitives {
			if _, ok := (p.Primitive).(tink.MAC); !ok {
				return nil, fmt.Errorf("mac_factory: not an MAC primitive")
			}
		}
	}

	ret := new(wrappedMAC)
	ret.ps = ps

	return ret, nil
}

// ComputeMAC calculates a MAC over the given data using the primary primitive
// and returns the concatenation of the primary's identifier and the calculated mac.
func (m *wrappedMAC) ComputeMAC(data []byte) ([]byte, error) {
	primary := m.ps.Primary
	primitive, ok := (primary.Primitive).(tink.MAC)
	if !ok {
		return nil, fmt.Errorf("mac_factory: not a MAC primitive")
	}
	if m.ps.Primary.PrefixType == tinkpb.OutputPrefixType_LEGACY {
		d := data
		data = make([]byte, 0, len(d)+1)
		data = append(data, d...)
		data = append(data, byte(0))
	}
	mac, err := primitive.ComputeMAC(data)
	if err != nil {
		return nil, err
	}
	return append([]byte(primary.Prefix), mac...), nil
}

var errInvalidMAC = fmt.Errorf("mac_factory: invalid mac")

// VerifyMAC verifies whether the given mac is a correct authentication code
// for the given data.
func (m *wrappedMAC) VerifyMAC(mac, data []byte) error {
	// This also rejects raw MAC with size of 4 bytes or fewer. Those MACs are
	// clearly insecure, thus should be discouraged.
	prefixSize := cryptofmt.NonRawPrefixSize
	if len(mac) <= prefixSize {
		return errInvalidMAC
	}

	// try non raw keys
	prefix := mac[:prefixSize]
	macNoPrefix := mac[prefixSize:]
	entries, err := m.ps.EntriesForPrefix(string(prefix))
	if err == nil {
		for i := 0; i < len(entries); i++ {
			entry := entries[i]
			p, ok := (entry.Primitive).(tink.MAC)
			if !ok {
				return fmt.Errorf("mac_factory: not an MAC primitive")
			}
			if entry.PrefixType == tinkpb.OutputPrefixType_LEGACY {
				d := data
				data = make([]byte, 0, len(d)+1)
				data = append(data, d...)
				data = append(data, byte(0))
			}
			if err = p.VerifyMAC(macNoPrefix, data); err == nil {
				return nil
			}
		}
	}

	// try raw keys
	entries, err = m.ps.RawEntries()
	if err == nil {
		for i := 0; i < len(entries); i++ {
			p, ok := (entries[i].Primitive).(tink.MAC)
			if !ok {
				return fmt.Errorf("mac_factory: not an MAC primitive")
			}

			if err = p.VerifyMAC(mac, data); err == nil {
				return nil
			}
		}
	}

	// nothing worked
	return errInvalidMAC
}
<commit_msg>Remove some unused flags.<commit_after>// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////

package mac

import (
	"fmt"

	"github.com/google/tink/go/core/cryptofmt"
	"github.com/google/tink/go/core/primitiveset"
	"github.com/google/tink/go/core/registry"
	"github.com/google/tink/go/keyset"
	"github.com/google/tink/go/tink"
	tinkpb "github.com/google/tink/go/proto/tink_go_proto"
)

// New creates a MAC primitive from the given keyset handle.
func New(h *keyset.Handle) (tink.MAC, error) {
	return NewWithKeyManager(h, nil /*keyManager*/)
}

// NewWithKeyManager creates a MAC primitive from the given keyset handle and a custom key manager.
// Deprecated: register the KeyManager and use New above.
func NewWithKeyManager(h *keyset.Handle, km registry.KeyManager) (tink.MAC, error) {
	ps, err := h.PrimitivesWithKeyManager(km)
	if err != nil {
		return nil, fmt.Errorf("mac_factory: cannot obtain primitive set: %s", err)
	}

	return newWrappedMAC(ps)
}

// wrappedMAC is a MAC implementation that uses the underlying primitive set to compute and
// verify MACs.
type wrappedMAC struct {
	ps *primitiveset.PrimitiveSet
}

func newWrappedMAC(ps *primitiveset.PrimitiveSet) (*wrappedMAC, error) {
	if _, ok := (ps.Primary.Primitive).(tink.MAC); !ok {
		return nil, fmt.Errorf("mac_factory: not a MAC primitive")
	}

	for _, primitives := range ps.Entries {
		for _, p := range primitives {
			if _, ok := (p.Primitive).(tink.MAC); !ok {
				return nil, fmt.Errorf("mac_factory: not an MAC primitive")
			}
		}
	}

	ret := new(wrappedMAC)
	ret.ps = ps

	return ret, nil
}

// ComputeMAC calculates a MAC over the given data using the primary primitive
// and returns the concatenation of the primary's identifier and the calculated mac.
func (m *wrappedMAC) ComputeMAC(data []byte) ([]byte, error) {
	primary := m.ps.Primary
	primitive, ok := (primary.Primitive).(tink.MAC)
	if !ok {
		return nil, fmt.Errorf("mac_factory: not a MAC primitive")
	}
	if m.ps.Primary.PrefixType == tinkpb.OutputPrefixType_LEGACY {
		d := data
		data = make([]byte, 0, len(d)+1)
		data = append(data, d...)
		data = append(data, byte(0))
	}
	mac, err := primitive.ComputeMAC(data)
	if err != nil {
		return nil, err
	}
	return append([]byte(primary.Prefix), mac...), nil
}

var errInvalidMAC = fmt.Errorf("mac_factory: invalid mac")

// VerifyMAC verifies whether the given mac is a correct authentication code
// for the given data.
func (m *wrappedMAC) VerifyMAC(mac, data []byte) error {
	// This also rejects raw MAC with size of 4 bytes or fewer. Those MACs are
	// clearly insecure, thus should be discouraged.
	prefixSize := cryptofmt.NonRawPrefixSize
	if len(mac) <= prefixSize {
		return errInvalidMAC
	}

	// try non raw keys
	prefix := mac[:prefixSize]
	macNoPrefix := mac[prefixSize:]
	entries, err := m.ps.EntriesForPrefix(string(prefix))
	if err == nil {
		for i := 0; i < len(entries); i++ {
			entry := entries[i]
			p, ok := (entry.Primitive).(tink.MAC)
			if !ok {
				return fmt.Errorf("mac_factory: not an MAC primitive")
			}
			if entry.PrefixType == tinkpb.OutputPrefixType_LEGACY {
				d := data
				data = make([]byte, 0, len(d)+1)
				data = append(data, d...)
				data = append(data, byte(0))
			}
			if err = p.VerifyMAC(macNoPrefix, data); err == nil {
				return nil
			}
		}
	}

	// try raw keys
	entries, err = m.ps.RawEntries()
	if err == nil {
		for i := 0; i < len(entries); i++ {
			p, ok := (entries[i].Primitive).(tink.MAC)
			if !ok {
				return fmt.Errorf("mac_factory: not an MAC primitive")
			}

			if err = p.VerifyMAC(mac, data); err == nil {
				return nil
			}
		}
	}

	// nothing worked
	return errInvalidMAC
}
<|endoftext|>


<commit_before>// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package ssa_test

// This file runs the SSA builder in sanity-checking mode on all
// packages beneath $GOROOT and prints some summary information.
//
// Run test with GOMAXPROCS=8.

import (
	"go/build"
	"go/token"
	"runtime"
	"testing"
	"time"

	"golang.org/x/tools/go/buildutil"
	"golang.org/x/tools/go/loader"
	"golang.org/x/tools/go/ssa"
	"golang.org/x/tools/go/ssa/ssautil"
)

func TestStdlib(t *testing.T) {
	// Load, parse and type-check the program.
	t0 := time.Now()

	// Load, parse and type-check the program.
	ctxt := build.Default // copy
	ctxt.GOPATH = ""      // disable GOPATH
	conf := loader.Config{
		SourceImports: true,
		Build:         &ctxt,
	}
	if _, err := conf.FromArgs(buildutil.AllPackages(conf.Build), true); err != nil {
		t.Errorf("FromArgs failed: %v", err)
		return
	}

	iprog, err := conf.Load()
	if err != nil {
		t.Fatalf("Load failed: %v", err)
	}

	t1 := time.Now()

	runtime.GC()
	var memstats runtime.MemStats
	runtime.ReadMemStats(&memstats)
	alloc := memstats.Alloc

	// Create SSA packages.
	var mode ssa.BuilderMode
	// Comment out these lines during benchmarking.  Approx SSA build costs are noted.
	mode |= ssa.SanityCheckFunctions // + 2% space, + 4% time
	mode |= ssa.GlobalDebug          // +30% space, +18% time
	prog := ssa.Create(iprog, mode)

	t2 := time.Now()

	// Build SSA.
	prog.BuildAll()

	t3 := time.Now()

	runtime.GC()
	runtime.ReadMemStats(&memstats)

	numPkgs := len(prog.AllPackages())
	if want := 140; numPkgs < want {
		t.Errorf("Loaded only %d packages, want at least %d", numPkgs, want)
	}

	allFuncs := ssautil.AllFunctions(prog)

	// Check that all non-synthetic functions have distinct names.
	byName := make(map[string]*ssa.Function)
	for fn := range allFuncs {
		if fn.Synthetic == "" {
			str := fn.String()
			prev := byName[str]
			byName[str] = fn
			if prev != nil {
				t.Errorf("%s: duplicate function named %s",
					prog.Fset.Position(fn.Pos()), str)
				t.Errorf("%s:   (previously defined here)",
					prog.Fset.Position(prev.Pos()))
			}
		}
	}

	// Dump some statistics.
	var numInstrs int
	for fn := range allFuncs {
		for _, b := range fn.Blocks {
			numInstrs += len(b.Instrs)
		}
	}

	// determine line count
	var lineCount int
	prog.Fset.Iterate(func(f *token.File) bool {
		lineCount += f.LineCount()
		return true
	})

	// NB: when benchmarking, don't forget to clear the debug +
	// sanity builder flags for better performance.

	t.Log("GOMAXPROCS:           ", runtime.GOMAXPROCS(0))
	t.Log("#Source lines:        ", lineCount)
	t.Log("Load/parse/typecheck: ", t1.Sub(t0))
	t.Log("SSA create:           ", t2.Sub(t1))
	t.Log("SSA build:            ", t3.Sub(t2))

	// SSA stats:
	t.Log("#Packages:            ", numPkgs)
	t.Log("#Functions:           ", len(allFuncs))
	t.Log("#Instructions:        ", numInstrs)
	t.Log("#MB:                  ", int64(memstats.Alloc-alloc)/1000000)
}
<commit_msg>go/ssa: report memory consumption separated by phase in stdlib_test<commit_after>// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package ssa_test

// This file runs the SSA builder in sanity-checking mode on all
// packages beneath $GOROOT and prints some summary information.
//
// Run with "go test -cpu=8 to" set GOMAXPROCS.

import (
	"go/build"
	"go/token"
	"runtime"
	"testing"
	"time"

	"golang.org/x/tools/go/buildutil"
	"golang.org/x/tools/go/loader"
	"golang.org/x/tools/go/ssa"
	"golang.org/x/tools/go/ssa/ssautil"
)

func bytesAllocated() uint64 {
	runtime.GC()
	var stats runtime.MemStats
	runtime.ReadMemStats(&stats)
	return stats.Alloc
}

func TestStdlib(t *testing.T) {
	// Load, parse and type-check the program.
	t0 := time.Now()
	alloc0 := bytesAllocated()

	// Load, parse and type-check the program.
	ctxt := build.Default // copy
	ctxt.GOPATH = ""      // disable GOPATH
	conf := loader.Config{
		SourceImports: true,
		Build:         &ctxt,
	}
	if _, err := conf.FromArgs(buildutil.AllPackages(conf.Build), true); err != nil {
		t.Errorf("FromArgs failed: %v", err)
		return
	}

	iprog, err := conf.Load()
	if err != nil {
		t.Fatalf("Load failed: %v", err)
	}

	t1 := time.Now()
	alloc1 := bytesAllocated()

	// Create SSA packages.
	var mode ssa.BuilderMode
	// Comment out these lines during benchmarking.  Approx SSA build costs are noted.
	mode |= ssa.SanityCheckFunctions // + 2% space, + 4% time
	mode |= ssa.GlobalDebug          // +30% space, +18% time
	prog := ssa.Create(iprog, mode)

	t2 := time.Now()

	// Build SSA.
	prog.BuildAll()

	t3 := time.Now()
	alloc3 := bytesAllocated()

	numPkgs := len(prog.AllPackages())
	if want := 140; numPkgs < want {
		t.Errorf("Loaded only %d packages, want at least %d", numPkgs, want)
	}

	// Keep iprog reachable until after we've measured memory usage.
	if len(iprog.AllPackages) == 0 {
		print() // unreachable
	}

	allFuncs := ssautil.AllFunctions(prog)

	// Check that all non-synthetic functions have distinct names.
	byName := make(map[string]*ssa.Function)
	for fn := range allFuncs {
		if fn.Synthetic == "" {
			str := fn.String()
			prev := byName[str]
			byName[str] = fn
			if prev != nil {
				t.Errorf("%s: duplicate function named %s",
					prog.Fset.Position(fn.Pos()), str)
				t.Errorf("%s:   (previously defined here)",
					prog.Fset.Position(prev.Pos()))
			}
		}
	}

	// Dump some statistics.
	var numInstrs int
	for fn := range allFuncs {
		for _, b := range fn.Blocks {
			numInstrs += len(b.Instrs)
		}
	}

	// determine line count
	var lineCount int
	prog.Fset.Iterate(func(f *token.File) bool {
		lineCount += f.LineCount()
		return true
	})

	// NB: when benchmarking, don't forget to clear the debug +
	// sanity builder flags for better performance.

	t.Log("GOMAXPROCS:           ", runtime.GOMAXPROCS(0))
	t.Log("#Source lines:        ", lineCount)
	t.Log("Load/parse/typecheck: ", t1.Sub(t0))
	t.Log("SSA create:           ", t2.Sub(t1))
	t.Log("SSA build:            ", t3.Sub(t2))

	// SSA stats:
	t.Log("#Packages:            ", numPkgs)
	t.Log("#Functions:           ", len(allFuncs))
	t.Log("#Instructions:        ", numInstrs)
	t.Log("#MB AST+types:        ", int64(alloc1-alloc0)/1e6)
	t.Log("#MB SSA:              ", int64(alloc3-alloc1)/1e6)
}
<|endoftext|>


<commit_before>// Copyright 2019 The Ebiten Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//go:build darwin && !ios
// +build darwin,!ios

package metal

import (
	"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/metal/mtl"
	"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/metal/ns"
)

func (v *view) setWindow(window uintptr) {
	// NSView can be updated e.g., fullscreen-state is switched.
	v.window = window
	v.windowChanged = true
}

func (v *view) setUIView(uiview uintptr) {
	panic("metal: setUIView is not available on macOS")
}

func (v *view) update() {
	if !v.windowChanged {
		return
	}

	cocoaWindow := ns.NewWindow(v.window)
	cocoaWindow.ContentView().SetLayer(v.ml)
	cocoaWindow.ContentView().SetWantsLayer(true)
	v.windowChanged = false
}

func (v *view) usePresentsWithTransaction() bool {
	// Disable presentsWithTransaction on the fullscreen mode (#1745).
	return !v.vsyncDisabled
}

func (v *view) maximumDrawableCount() int {
	// When presentsWithTransaction is YES and triple buffering is enabled, nextDrawing returns immediately once every two times.
	// This makes FPS doubled. To avoid this, disable the triple buffering.
	if v.usePresentsWithTransaction() {
		return 2
	}
	return 3
}

const (
	storageMode         = mtl.StorageModeManaged
	resourceStorageMode = mtl.ResourceStorageModeManaged
)
<commit_msg>internal/graphicsdriver/metal: Bug fix: Vsync didn't work on macOS<commit_after>// Copyright 2019 The Ebiten Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//go:build darwin && !ios
// +build darwin,!ios

package metal

// #cgo CFLAGS: -x objective-c
// #cgo LDFLAGS: -framework Foundation
//
// #import <Foundation/Foundation.h>
//
// static int getMacOSMajorVersion() {
//   NSOperatingSystemVersion version = [[NSProcessInfo processInfo] operatingSystemVersion];
//   return (int)version.majorVersion;
// }
import "C"

import (
	"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/metal/mtl"
	"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/metal/ns"
)

var macOSMajorVersion = int(C.getMacOSMajorVersion())

func (v *view) setWindow(window uintptr) {
	// NSView can be updated e.g., fullscreen-state is switched.
	v.window = window
	v.windowChanged = true
}

func (v *view) setUIView(uiview uintptr) {
	panic("metal: setUIView is not available on macOS")
}

func (v *view) update() {
	if !v.windowChanged {
		return
	}

	cocoaWindow := ns.NewWindow(v.window)
	cocoaWindow.ContentView().SetLayer(v.ml)
	cocoaWindow.ContentView().SetWantsLayer(true)
	v.windowChanged = false
}

func (v *view) usePresentsWithTransaction() bool {
	// On macOS 12 (or later), do not use presentsWithTransaction, or vsync doesn't work (#1885).
	// This works only for Metal. Unfortunately, there is not a good solution for OpenGL.
	if macOSMajorVersion >= 12 {
		return false
	}

	// Disable presentsWithTransaction on the fullscreen mode (#1745).
	return !v.vsyncDisabled
}

func (v *view) maximumDrawableCount() int {
	// When presentsWithTransaction is YES and triple buffering is enabled, nextDrawing returns immediately once every two times.
	// This makes FPS doubled. To avoid this, disable the triple buffering.
	if v.usePresentsWithTransaction() {
		return 2
	}
	return 3
}

const (
	storageMode         = mtl.StorageModeManaged
	resourceStorageMode = mtl.ResourceStorageModeManaged
)
<|endoftext|>


<commit_before>// Copyright 2011 Google Inc. All Rights Reserved.
// This file is available under the Apache license.
// +build integration

package mtail_test

import (
	"fmt"
	"os"
	"path"
	"path/filepath"
	"sync"
	"testing"

	"github.com/google/mtail/internal/metrics"
	"github.com/google/mtail/internal/metrics/datum"
	"github.com/google/mtail/internal/mtail"
	"github.com/google/mtail/internal/mtail/golden"
	"github.com/google/mtail/internal/testutil"
	"github.com/google/mtail/internal/watcher"
)

var exampleProgramTests = []struct {
	programfile string // Example program file.
	logfile     string // Sample log input.
	goldenfile  string // Expected metrics after processing.
}{
	{
		"examples/rsyncd.mtail",
		"testdata/rsyncd.log",
		"testdata/rsyncd.golden",
	},
	{
		"examples/sftp.mtail",
		"testdata/sftp_chroot.log",
		"testdata/sftp_chroot.golden",
	},
	{
		"examples/dhcpd.mtail",
		"testdata/anonymised_dhcpd_log",
		"testdata/anonymised_dhcpd_log.golden",
	},
	{
		"examples/ntpd.mtail",
		"testdata/ntp4",
		"testdata/ntp4.golden",
	},
	{
		"examples/ntpd_peerstats.mtail",
		"testdata/xntp3_peerstats",
		"testdata/xntp3_peerstats.golden",
	},
	{
		"examples/otherwise.mtail",
		"testdata/otherwise.log",
		"testdata/otherwise.golden",
	},
	{
		"examples/else.mtail",
		"testdata/else.log",
		"testdata/else.golden",
	},
	{
		"examples/types.mtail",
		"testdata/types.log",
		"testdata/types.golden",
	},
	{
		"examples/filename.mtail",
		"testdata/else.log",
		"testdata/filename.golden",
	},
	{
		"examples/logical.mtail",
		"testdata/logical.log",
		"testdata/logical.golden",
	},
	{
		"examples/strcat.mtail",
		"testdata/strcat.log",
		"testdata/strcat.golden",
	},
	{
		"examples/add_assign_float.mtail",
		"testdata/add_assign_float.log",
		"testdata/add_assign_float.golden",
	},
	{
		"examples/typed-comparison.mtail",
		"testdata/typed-comparison.log",
		"testdata/typed-comparison.golden",
	},
	{
		"examples/match-expression.mtail",
		"testdata/match-expression.log",
		"testdata/match-expression.golden",
	},
	{
		"examples/apache_combined.mtail",
		"testdata/apache-combined.log",
		"testdata/apache-combined.golden",
	},
	{
		"examples/apache_common.mtail",
		"testdata/apache-common.log",
		"testdata/apache-common.golden",
	},
	{
		"examples/metric-as-rvalue.mtail",
		"testdata/metric-as-rvalue.log",
		"testdata/metric-as-rvalue.golden",
	},
	{
		"examples/decorator.mtail",
		"testdata/decorator.log",
		"testdata/decorator.golden",
	},
	{
		"examples/stringy.mtail",
		"testdata/stringy.log",
		"testdata/stringy.golden",
	},
	{
		"examples/ip-addr.mtail",
		"testdata/ip-addr.log",
		"testdata/ip-addr.golden",
	},
	{
		"examples/vsftpd.mtail",
		"testdata/vsftpd_log",
		"testdata/vsftpd_log.golden",
	},
	{
		"examples/vsftpd.mtail",
		"testdata/vsftpd_xferlog",
		"testdata/vsftpd_xferlog.golden",
	},
	{
		"examples/lighttpd.mtail",
		"testdata/lighttpd_access.log",
		"testdata/lighttpd_accesslog.golden",
	},
	{
		"examples/mysql_slowqueries.mtail",
		"testdata/mysql_slowqueries.log",
		"testdata/mysql_slowqueries.golden",
	},
}

func TestExamplePrograms(t *testing.T) {
	if testing.Short() {
		t.Skip("skipping test in short mode")
	}
	for _, tc := range exampleProgramTests {
		t.Run(fmt.Sprintf("%s on %s", tc.programfile, tc.logfile), func(t *testing.T) {
			w := watcher.NewFakeWatcher()
			store := metrics.NewStore()
			programFile := path.Join("../..", tc.programfile)
			mtail, err := mtail.New(store, w, mtail.ProgramPath(programFile), mtail.LogPathPatterns(tc.logfile), mtail.OneShot, mtail.OmitMetricSource, mtail.DumpAstTypes, mtail.DumpBytecode)
			if err != nil {
				t.Fatalf("create mtail failed: %s", err)
			}

			err = mtail.StartTailing()
			if err != nil {
				t.Fatalf("Start tailling failed: %s", err)
			}

			g, err := os.Open(tc.goldenfile)
			if err != nil {
				t.Fatalf("could not open golden file: %s", err)
			}
			defer g.Close()

			goldenStore := metrics.NewStore()
			golden.ReadTestData(g, tc.programfile, goldenStore)

			err = mtail.Close()
			if err != nil {
				t.Error(err)
			}

			diff := testutil.Diff(goldenStore, store, testutil.IgnoreUnexported(sync.RWMutex{}, datum.StringDatum{}))

			if diff != "" {
				t.Error(diff)
				t.Logf(" Golden metrics: %s", goldenStore.Metrics)
				t.Logf("Program metrics: %s", store.Metrics)
				t.Logf("yar\n%+v", store.Metrics)
			}
		})
	}
}

// This test only compiles examples, but has coverage over all examples
// provided.  This ensures we ship at least syntactically correct examples.
func TestCompileExamplePrograms(t *testing.T) {
	if testing.Short() {
		t.Skip("skipping test in short mode")
	}
	matches, err := filepath.Glob("examples/*.mtail")
	if err != nil {
		t.Fatal(err)
	}
	for _, tc := range matches {
		t.Run(tc, func(t *testing.T) {
			w := watcher.NewFakeWatcher()
			s := metrics.NewStore()
			mtail, err := mtail.New(s, w, mtail.ProgramPath(tc), mtail.CompileOnly, mtail.OmitMetricSource, mtail.DumpAstTypes, mtail.DumpBytecode)
			if err != nil {
				t.Fatal(err)
			}
			mtail.Close()
		})
	}
}
<commit_msg>Fix the examples compilation test.<commit_after>// Copyright 2011 Google Inc. All Rights Reserved.
// This file is available under the Apache license.
// +build integration

package mtail_test

import (
	"fmt"
	"os"
	"path"
	"path/filepath"
	"sync"
	"testing"

	"github.com/google/mtail/internal/metrics"
	"github.com/google/mtail/internal/metrics/datum"
	"github.com/google/mtail/internal/mtail"
	"github.com/google/mtail/internal/mtail/golden"
	"github.com/google/mtail/internal/testutil"
	"github.com/google/mtail/internal/watcher"
)

var exampleProgramTests = []struct {
	programfile string // Example program file.
	logfile     string // Sample log input.
	goldenfile  string // Expected metrics after processing.
}{
	{
		"examples/rsyncd.mtail",
		"testdata/rsyncd.log",
		"testdata/rsyncd.golden",
	},
	{
		"examples/sftp.mtail",
		"testdata/sftp_chroot.log",
		"testdata/sftp_chroot.golden",
	},
	{
		"examples/dhcpd.mtail",
		"testdata/anonymised_dhcpd_log",
		"testdata/anonymised_dhcpd_log.golden",
	},
	{
		"examples/ntpd.mtail",
		"testdata/ntp4",
		"testdata/ntp4.golden",
	},
	{
		"examples/ntpd_peerstats.mtail",
		"testdata/xntp3_peerstats",
		"testdata/xntp3_peerstats.golden",
	},
	{
		"examples/otherwise.mtail",
		"testdata/otherwise.log",
		"testdata/otherwise.golden",
	},
	{
		"examples/else.mtail",
		"testdata/else.log",
		"testdata/else.golden",
	},
	{
		"examples/types.mtail",
		"testdata/types.log",
		"testdata/types.golden",
	},
	{
		"examples/filename.mtail",
		"testdata/else.log",
		"testdata/filename.golden",
	},
	{
		"examples/logical.mtail",
		"testdata/logical.log",
		"testdata/logical.golden",
	},
	{
		"examples/strcat.mtail",
		"testdata/strcat.log",
		"testdata/strcat.golden",
	},
	{
		"examples/add_assign_float.mtail",
		"testdata/add_assign_float.log",
		"testdata/add_assign_float.golden",
	},
	{
		"examples/typed-comparison.mtail",
		"testdata/typed-comparison.log",
		"testdata/typed-comparison.golden",
	},
	{
		"examples/match-expression.mtail",
		"testdata/match-expression.log",
		"testdata/match-expression.golden",
	},
	{
		"examples/apache_combined.mtail",
		"testdata/apache-combined.log",
		"testdata/apache-combined.golden",
	},
	{
		"examples/apache_common.mtail",
		"testdata/apache-common.log",
		"testdata/apache-common.golden",
	},
	{
		"examples/metric-as-rvalue.mtail",
		"testdata/metric-as-rvalue.log",
		"testdata/metric-as-rvalue.golden",
	},
	{
		"examples/decorator.mtail",
		"testdata/decorator.log",
		"testdata/decorator.golden",
	},
	{
		"examples/stringy.mtail",
		"testdata/stringy.log",
		"testdata/stringy.golden",
	},
	{
		"examples/ip-addr.mtail",
		"testdata/ip-addr.log",
		"testdata/ip-addr.golden",
	},
	{
		"examples/vsftpd.mtail",
		"testdata/vsftpd_log",
		"testdata/vsftpd_log.golden",
	},
	{
		"examples/vsftpd.mtail",
		"testdata/vsftpd_xferlog",
		"testdata/vsftpd_xferlog.golden",
	},
	{
		"examples/lighttpd.mtail",
		"testdata/lighttpd_access.log",
		"testdata/lighttpd_accesslog.golden",
	},
	{
		"examples/mysql_slowqueries.mtail",
		"testdata/mysql_slowqueries.log",
		"testdata/mysql_slowqueries.golden",
	},
}

func TestExamplePrograms(t *testing.T) {
	if testing.Short() {
		t.Skip("skipping test in short mode")
	}
	for _, tc := range exampleProgramTests {
		t.Run(fmt.Sprintf("%s on %s", tc.programfile, tc.logfile), func(t *testing.T) {
			w := watcher.NewFakeWatcher()
			store := metrics.NewStore()
			programFile := path.Join("../..", tc.programfile)
			mtail, err := mtail.New(store, w, mtail.ProgramPath(programFile), mtail.LogPathPatterns(tc.logfile), mtail.OneShot, mtail.OmitMetricSource, mtail.DumpAstTypes, mtail.DumpBytecode)
			if err != nil {
				t.Fatalf("create mtail failed: %s", err)
			}

			err = mtail.StartTailing()
			if err != nil {
				t.Fatalf("Start tailling failed: %s", err)
			}

			g, err := os.Open(tc.goldenfile)
			if err != nil {
				t.Fatalf("could not open golden file: %s", err)
			}
			defer g.Close()

			goldenStore := metrics.NewStore()
			golden.ReadTestData(g, tc.programfile, goldenStore)

			err = mtail.Close()
			if err != nil {
				t.Error(err)
			}

			diff := testutil.Diff(goldenStore, store, testutil.IgnoreUnexported(sync.RWMutex{}, datum.StringDatum{}))

			if diff != "" {
				t.Error(diff)
				t.Logf(" Golden metrics: %s", goldenStore.Metrics)
				t.Logf("Program metrics: %s", store.Metrics)
				t.Logf("yar\n%+v", store.Metrics)
			}
		})
	}
}

// This test only compiles examples, but has coverage over all examples
// provided.  This ensures we ship at least syntactically correct examples.
func TestCompileExamplePrograms(t *testing.T) {
	if testing.Short() {
		t.Skip("skipping test in short mode")
	}
	matches, err := filepath.Glob("../../examples/*.mtail")
	if err != nil {
		t.Fatal(err)
	}
	for _, tc := range matches {
		name := filepath.Base(tc)
		t.Run(name, func(t *testing.T) {
			w := watcher.NewFakeWatcher()
			s := metrics.NewStore()
			mtail, err := mtail.New(s, w, mtail.ProgramPath(tc), mtail.CompileOnly, mtail.OmitMetricSource, mtail.DumpAstTypes, mtail.DumpBytecode)
			if err != nil {
				t.Fatal(err)
			}
			mtail.Close()
		})
	}
}
<|endoftext|>


<commit_before>package gaestatic

import (
	"strings"
	"fmt"
	"strconv"
	"net/http"
	"text/template"
	"bytes"
)

const PLIST_TEMPLATE string = `<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
	<dict>
		<key>items</key>
		<array>
			<dict>
				<key>assets</key>
				<array>
					{{if .IpaUrl}}
					<dict>
						<key>kind</key>
						<string>software-package</string>
						<key>url</key>
						<string>{{.IpaUrl}}</string>
					</dict>
					{{end}}
					{{if .DisplayImageUrl}}
					<dict>
						<key>kind</key>
						<string>display-image</string>
						<key>url</key>
						<string>{{.DisplayImageUrl}}</string>
					</dict>
					{{end}}
					{{if .FullSizeImageUrl}}
					<dict>
						<key>kind</key>
						<string>full-size-image</string>
						<key>url</key>
						<string>{{.FullSizeImageUrl}}</string>
					</dict>
					{{end}}
				</array>
				<key>metadata</key>
				<dict>
					{{if .BundleIdentifer}}
					<key>bundle-identifier</key>
					<string>{{.BundleIdentifer}}</string>
					{{end}}
					{{if .BundleVersion}}
					<key>bundle-version</key>
					<string>{{.BundleVersion}}</string>
					<key>kind</key>
					{{end}}
					{{if .Title}}
					<string>software</string>
					<key>title</key>
					<string>{{.Title}}</string>
					{{end}}
				</dict>
			</dict>
		</array>
	</dict>
</plist>
`

type PlistTemplateParams struct {
	// eg. https://example.com/apps/ios/sample.ipa
	IpaUrl string
	// eg. https://example.com/apps/ios/image.png
	DisplayImageUrl string
	// eg. https://example.com/apps/ios/full-image.png
	FullSizeImageUrl string
	// eg. com.example.sample
	BundleIdentifer string
	// eg. 1.0
	BundleVersion string
	// eg. Sample App
	Title string
}

/**
 * Dynamic Plist Handler
 */
func plistHandler(w http.ResponseWriter, r *http.Request) bool {

	isDone := true

	config := GetAppConfig()
	if config == nil {
		// Internal Server Errror
		w.WriteHeader(500)
		w.Write([]byte("No Config"))
		return isDone
	}

	filePath := strings.Replace(r.URL.Path, config.PlistDir, "", 1)
	tmp := strings.SplitN(filePath, "/", 2)
	if len(tmp) < 2 {
		// Bad Request
		w.WriteHeader(400)
		w.Write([]byte("invalid path #1"))
		return isDone
	}
	bundleIdentifer := tmp[0]
	if strings.Contains(tmp[1], "..") {
		// Bad Request
		w.WriteHeader(400)
		w.Write([]byte("invalid path #2"))
		return isDone
	}

	ipaUrl := r.URL
	ipaUrl.Path = "/" + tmp[1]

	params := PlistTemplateParams{}
	// http://example.com/{filePath}/{bundleId}/{IpaPath}?title={title}&version={bundleVersion}
	params.Title = r.URL.Query().Get("title")
	params.BundleVersion = r.URL.Query().Get("version")
	params.BundleIdentifer = bundleIdentifer
	params.IpaUrl = ipaUrl.String()

	tmpl, err := template.New("plist").Parse(PLIST_TEMPLATE)

	if err != nil {
		// Not Found
		w.WriteHeader(501)
		w.Write([]byte(fmt.Sprintf("plist template is invalid.")))
		return isDone
	}

	writer := new(bytes.Buffer)
	err	= tmpl.Execute(writer, params)

	var contentLength string
	if err != nil {
		// Forbidden : サイズ取得失敗
		w.WriteHeader(403)
		w.Write([]byte(fmt.Sprintf("plist params is invalid.")))
		return isDone
	} else {
		contentLength = strconv.FormatInt(int64(writer.Len()), 10)
	}
	contentLength = contentLength + "bytes"

	contentType := GetContentType("_.plist")
	if contentType != "" {
		w.Header().Set("Content-Type", contentType)
	}
	w.Write(writer.Bytes())
	isDone = true
	return isDone
}
<commit_msg>dynamic plist : snapshot<commit_after>package gaestatic

import (
	"strings"
	"fmt"
	"strconv"
	"net/http"
	"text/template"
	"bytes"
	"net/url"
)

const PLIST_TEMPLATE string = `<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
	<dict>
		<key>items</key>
		<array>
			<dict>
				<key>assets</key>
				<array>
					{{if .IpaUrl}}
					<dict>
						<key>kind</key>
						<string>software-package</string>
						<key>url</key>
						<string>{{.IpaUrl}}</string>
					</dict>
					{{end}}
					{{if .DisplayImageUrl}}
					<dict>
						<key>kind</key>
						<string>display-image</string>
						<key>url</key>
						<string>{{.DisplayImageUrl}}</string>
					</dict>
					{{end}}
					{{if .FullSizeImageUrl}}
					<dict>
						<key>kind</key>
						<string>full-size-image</string>
						<key>url</key>
						<string>{{.FullSizeImageUrl}}</string>
					</dict>
					{{end}}
				</array>
				<key>metadata</key>
				<dict>
					{{if .BundleIdentifer}}
					<key>bundle-identifier</key>
					<string>{{.BundleIdentifer}}</string>
					{{end}}
					{{if .BundleVersion}}
					<key>bundle-version</key>
					<string>{{.BundleVersion}}</string>
					<key>kind</key>
					{{end}}
					{{if .Title}}
					<string>software</string>
					<key>title</key>
					<string>{{.Title}}</string>
					{{end}}
				</dict>
			</dict>
		</array>
	</dict>
</plist>
`

type PlistTemplateParams struct {
	// eg. https://example.com/apps/ios/sample.ipa
	IpaUrl string
	// eg. https://example.com/apps/ios/image.png
	DisplayImageUrl string
	// eg. https://example.com/apps/ios/full-image.png
	FullSizeImageUrl string
	// eg. com.example.sample
	BundleIdentifer string
	// eg. 1.0
	BundleVersion string
	// eg. Sample App
	Title string
}

/**
 * Dynamic Plist Handler
 */
func plistHandler(w http.ResponseWriter, r *http.Request) bool {

	isDone := true

	config := GetAppConfig()
	if config == nil {
		// Internal Server Errror
		w.WriteHeader(500)
		w.Write([]byte("No Config"))
		return isDone
	}

	filePath := strings.Replace(r.URL.Path, config.PlistDir, "", 1)
	tmp := strings.SplitN(filePath, "/", 2)
	if len(tmp) < 2 {
		// Bad Request
		w.WriteHeader(400)
		w.Write([]byte("invalid path #1"))
		return isDone
	}
	bundleIdentifer := tmp[0]
	if strings.Contains(tmp[1], "..") {
		// Bad Request
		w.WriteHeader(400)
		w.Write([]byte("invalid path #2"))
		return isDone
	}

	ipaUrl, _ := url.Parse(r.RequestURI)
	ipaUrl.Path = "/" + tmp[1]

	params := PlistTemplateParams{}
	// http://example.com/{filePath}/{bundleId}/{IpaPath}?title={title}&version={bundleVersion}
	params.Title = r.URL.Query().Get("title")
	params.BundleVersion = r.URL.Query().Get("version")
	params.BundleIdentifer = bundleIdentifer
	params.IpaUrl = ipaUrl.String()

	tmpl, err := template.New("plist").Parse(PLIST_TEMPLATE)

	if err != nil {
		// Not Found
		w.WriteHeader(501)
		w.Write([]byte(fmt.Sprintf("plist template is invalid.")))
		return isDone
	}

	writer := new(bytes.Buffer)
	err	= tmpl.Execute(writer, params)

	var contentLength string
	if err != nil {
		// Forbidden : サイズ取得失敗
		w.WriteHeader(403)
		w.Write([]byte(fmt.Sprintf("plist params is invalid.")))
		return isDone
	} else {
		contentLength = strconv.FormatInt(int64(writer.Len()), 10)
	}
	contentLength = contentLength + "bytes"

	contentType := GetContentType("_.plist")
	if contentType != "" {
		w.Header().Set("Content-Type", contentType)
	}
	w.Write(writer.Bytes())
	isDone = true
	return isDone
}
<|endoftext|>


<commit_before>// Copyright 2012, Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tabletserver

import (
	"sync"
	"time"

	log "github.com/golang/glog"

	"github.com/youtube/vitess/go/stats"
	"github.com/youtube/vitess/go/sync2"
	"github.com/youtube/vitess/go/vt/dbconfigs"
	"github.com/youtube/vitess/go/vt/dbconnpool"
	"github.com/youtube/vitess/go/vt/logutil"
	"github.com/youtube/vitess/go/vt/mysqlctl"
)

// spotCheckMultiplier determines the precision of the
// spot check ratio: 1e6 == 6 digits
const spotCheckMultiplier = 1e6

// QueryEngine implements the core functionality of tabletserver.
// It assumes that no requests will be sent to it before Open is
// called and succeeds.
// Shutdown is done in the following order:
//
// WaitForTxEmpty: There should be no more new calls to Begin
// once this function is called. This will return when there
// are no more pending transactions.
//
// Close: There should be no more pending queries when this
// function is called.
//
// Functions of QueryEngine do not return errors. They instead
// panic with NewTabletError as the error type.
// TODO(sougou): Switch to error return scheme.
type QueryEngine struct {
	schemaInfo *SchemaInfo
	dbconfigs  *dbconfigs.DBConfigs

	// Pools
	cachePool      *CachePool
	connPool       *dbconnpool.ConnectionPool
	streamConnPool *dbconnpool.ConnectionPool

	// Services
	txPool       *TxPool
	consolidator *Consolidator
	invalidator  *RowcacheInvalidator
	streamQList  *QueryList
	connKiller   *ConnectionKiller
	tasks        sync.WaitGroup

	// Vars
	queryTimeout     sync2.AtomicDuration
	spotCheckFreq    sync2.AtomicInt64
	strictMode       sync2.AtomicInt64
	maxResultSize    sync2.AtomicInt64
	maxDMLRows       sync2.AtomicInt64
	streamBufferSize sync2.AtomicInt64
	strictTableAcl   bool

	// loggers
	accessCheckerLogger *logutil.ThrottledLogger
}

type compiledPlan struct {
	Query string
	*ExecPlan
	BindVars      map[string]interface{}
	TransactionID int64
}

var (
	// stats are globals to allow anybody to set them
	mysqlStats     *stats.Timings
	queryStats     *stats.Timings
	waitStats      *stats.Timings
	killStats      *stats.Counters
	infoErrors     *stats.Counters
	errorStats     *stats.Counters
	internalErrors *stats.Counters
	resultStats    *stats.Histogram
	spotCheckCount *stats.Int
	QPSRates       *stats.Rates

	resultBuckets = []int64{0, 1, 5, 10, 50, 100, 500, 1000, 5000, 10000}

	connPoolClosedErr = NewTabletError(FATAL, "connection pool is closed")
)

// CacheInvalidator provides the abstraction needed for an instant invalidation
// vs. delayed invalidation in the case of in-transaction dmls
type CacheInvalidator interface {
	Delete(key string)
}

// Helper method for conn pools to convert errors
func getOrPanic(pool *dbconnpool.ConnectionPool) dbconnpool.PoolConnection {
	conn, err := pool.Get(0)
	if err == nil {
		return conn
	}
	if err == dbconnpool.CONN_POOL_CLOSED_ERR {
		panic(connPoolClosedErr)
	}
	panic(NewTabletErrorSql(FATAL, err))
}

// NewQueryEngine creates a new QueryEngine.
// This is a singleton class.
// You must call this only once.
func NewQueryEngine(config Config) *QueryEngine {
	qe := &QueryEngine{}
	qe.schemaInfo = NewSchemaInfo(
		config.QueryCacheSize,
		time.Duration(config.SchemaReloadTime*1e9),
		time.Duration(config.IdleTimeout*1e9),
	)

	mysqlStats = stats.NewTimings("Mysql")

	// Pools
	qe.cachePool = NewCachePool(
		"Rowcache",
		config.RowCache,
		time.Duration(config.QueryTimeout*1e9),
		time.Duration(config.IdleTimeout*1e9),
	)
	qe.connPool = dbconnpool.NewConnectionPool(
		"ConnPool",
		config.PoolSize,
		time.Duration(config.IdleTimeout*1e9),
	)
	qe.streamConnPool = dbconnpool.NewConnectionPool(
		"StreamConnPool",
		config.StreamPoolSize,
		time.Duration(config.IdleTimeout*1e9),
	)

	// Services
	qe.txPool = NewTxPool(
		"TransactionPool",
		config.TransactionCap,
		time.Duration(config.TransactionTimeout*1e9),
		time.Duration(config.TxPoolTimeout*1e9),
		time.Duration(config.IdleTimeout*1e9),
	)
	qe.connKiller = NewConnectionKiller(1, time.Duration(config.IdleTimeout*1e9))
	qe.consolidator = NewConsolidator()
	qe.invalidator = NewRowcacheInvalidator(qe)
	qe.streamQList = NewQueryList(qe.connKiller)

	// Vars
	qe.queryTimeout.Set(time.Duration(config.QueryTimeout * 1e9))
	qe.spotCheckFreq = sync2.AtomicInt64(config.SpotCheckRatio * spotCheckMultiplier)
	if config.StrictMode {
		qe.strictMode.Set(1)
	}
	qe.strictTableAcl = config.StrictTableAcl
	qe.maxResultSize = sync2.AtomicInt64(config.MaxResultSize)
	qe.maxDMLRows = sync2.AtomicInt64(config.MaxDMLRows)
	qe.streamBufferSize = sync2.AtomicInt64(config.StreamBufferSize)

	// loggers
	qe.accessCheckerLogger = logutil.NewThrottledLogger("accessChecker", 1*time.Second)

	// Stats
	stats.Publish("MaxResultSize", stats.IntFunc(qe.maxResultSize.Get))
	stats.Publish("MaxDMLRows", stats.IntFunc(qe.maxDMLRows.Get))
	stats.Publish("StreamBufferSize", stats.IntFunc(qe.streamBufferSize.Get))
	stats.Publish("QueryTimeout", stats.DurationFunc(qe.queryTimeout.Get))
	queryStats = stats.NewTimings("Queries")
	QPSRates = stats.NewRates("QPS", queryStats, 15, 60*time.Second)
	waitStats = stats.NewTimings("Waits")
	killStats = stats.NewCounters("Kills")
	infoErrors = stats.NewCounters("InfoErrors")
	errorStats = stats.NewCounters("Errors")
	internalErrors = stats.NewCounters("InternalErrors")
	resultStats = stats.NewHistogram("Results", resultBuckets)
	stats.Publish("RowcacheSpotCheckRatio", stats.FloatFunc(func() float64 {
		return float64(qe.spotCheckFreq.Get()) / spotCheckMultiplier
	}))
	spotCheckCount = stats.NewInt("RowcacheSpotCheckCount")

	return qe
}

// Open must be called before sending requests to QueryEngine.
func (qe *QueryEngine) Open(dbconfigs *dbconfigs.DBConfigs, schemaOverrides []SchemaOverride, qrs *QueryRules, mysqld *mysqlctl.Mysqld) {
	qe.dbconfigs = dbconfigs
	connFactory := dbconnpool.DBConnectionCreator(&dbconfigs.App.ConnectionParams, mysqlStats)
	// Create dba params based on App connection params
	// and Dba credentials.
	dba := dbconfigs.App.ConnectionParams
	dba.Uname = dbconfigs.Dba.Uname
	dba.Pass = dbconfigs.Dba.Pass
	dbaConnFactory := dbconnpool.DBConnectionCreator(&dba, mysqlStats)

	strictMode := false
	if qe.strictMode.Get() != 0 {
		strictMode = true
	}
	if !strictMode && dbconfigs.App.EnableRowcache {
		panic(NewTabletError(FATAL, "Rowcache cannot be enabled when queryserver-config-strict-mode is false"))
	}
	if dbconfigs.App.EnableRowcache {
		qe.cachePool.Open()
		log.Infof("rowcache is enabled")
	} else {
		// Invalidator should not be enabled if rowcache is not enabled.
		dbconfigs.App.EnableInvalidator = false
		log.Infof("rowcache is not enabled")
	}

	start := time.Now()
	// schemaInfo depends on cachePool. Every table that has a rowcache
	// points to the cachePool.
	qe.schemaInfo.Open(dbaConnFactory, schemaOverrides, qe.cachePool, qrs, strictMode)
	log.Infof("Time taken to load the schema: %v", time.Now().Sub(start))

	// Start the invalidator only after schema is loaded.
	// This will allow qe to find the table info
	// for the invalidation events that will start coming
	// immediately.
	if dbconfigs.App.EnableInvalidator {
		qe.invalidator.Open(dbconfigs.App.DbName, mysqld)
	}
	qe.connPool.Open(connFactory)
	qe.streamConnPool.Open(connFactory)
	qe.txPool.Open(connFactory)
	qe.connKiller.Open(dbaConnFactory)
}

// Launch launches the specified function inside a goroutine.
// If Close or WaitForTxEmpty is called while a goroutine is running,
// QueryEngine will not return until the existing functions have completed.
// This functionality allows us to launch tasks with the assurance that
// the QueryEngine will not be closed underneath us.
func (qe *QueryEngine) Launch(f func()) {
	qe.tasks.Add(1)
	go func() {
		defer func() {
			qe.tasks.Done()
			if x := recover(); x != nil {
				internalErrors.Add("Task", 1)
				log.Errorf("task error: %v", x)
			}
		}()
		f()
	}()
}

// WaitForTxEmpty must be called before calling Close.
// Before calling WaitForTxEmpty, you must ensure that there
// will be no more calls to Begin.
func (qe *QueryEngine) WaitForTxEmpty() {
	qe.txPool.WaitForEmpty()
}

// Close must be called to shut down QueryEngine.
// You must ensure that no more queries will be sent
// before calling Close.
func (qe *QueryEngine) Close() {
	qe.tasks.Wait()
	// Close in reverse order of Open.
	qe.connKiller.Close()
	qe.txPool.Close()
	qe.streamConnPool.Close()
	qe.connPool.Close()
	qe.invalidator.Close()
	qe.schemaInfo.Close()
	qe.cachePool.Close()
	qe.dbconfigs = nil
}
<commit_msg>tabletserver: use dba credentials only if supplied<commit_after>// Copyright 2012, Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tabletserver

import (
	"sync"
	"time"

	log "github.com/golang/glog"

	"github.com/youtube/vitess/go/stats"
	"github.com/youtube/vitess/go/sync2"
	"github.com/youtube/vitess/go/vt/dbconfigs"
	"github.com/youtube/vitess/go/vt/dbconnpool"
	"github.com/youtube/vitess/go/vt/logutil"
	"github.com/youtube/vitess/go/vt/mysqlctl"
)

// spotCheckMultiplier determines the precision of the
// spot check ratio: 1e6 == 6 digits
const spotCheckMultiplier = 1e6

// QueryEngine implements the core functionality of tabletserver.
// It assumes that no requests will be sent to it before Open is
// called and succeeds.
// Shutdown is done in the following order:
//
// WaitForTxEmpty: There should be no more new calls to Begin
// once this function is called. This will return when there
// are no more pending transactions.
//
// Close: There should be no more pending queries when this
// function is called.
//
// Functions of QueryEngine do not return errors. They instead
// panic with NewTabletError as the error type.
// TODO(sougou): Switch to error return scheme.
type QueryEngine struct {
	schemaInfo *SchemaInfo
	dbconfigs  *dbconfigs.DBConfigs

	// Pools
	cachePool      *CachePool
	connPool       *dbconnpool.ConnectionPool
	streamConnPool *dbconnpool.ConnectionPool

	// Services
	txPool       *TxPool
	consolidator *Consolidator
	invalidator  *RowcacheInvalidator
	streamQList  *QueryList
	connKiller   *ConnectionKiller
	tasks        sync.WaitGroup

	// Vars
	queryTimeout     sync2.AtomicDuration
	spotCheckFreq    sync2.AtomicInt64
	strictMode       sync2.AtomicInt64
	maxResultSize    sync2.AtomicInt64
	maxDMLRows       sync2.AtomicInt64
	streamBufferSize sync2.AtomicInt64
	strictTableAcl   bool

	// loggers
	accessCheckerLogger *logutil.ThrottledLogger
}

type compiledPlan struct {
	Query string
	*ExecPlan
	BindVars      map[string]interface{}
	TransactionID int64
}

var (
	// stats are globals to allow anybody to set them
	mysqlStats     *stats.Timings
	queryStats     *stats.Timings
	waitStats      *stats.Timings
	killStats      *stats.Counters
	infoErrors     *stats.Counters
	errorStats     *stats.Counters
	internalErrors *stats.Counters
	resultStats    *stats.Histogram
	spotCheckCount *stats.Int
	QPSRates       *stats.Rates

	resultBuckets = []int64{0, 1, 5, 10, 50, 100, 500, 1000, 5000, 10000}

	connPoolClosedErr = NewTabletError(FATAL, "connection pool is closed")
)

// CacheInvalidator provides the abstraction needed for an instant invalidation
// vs. delayed invalidation in the case of in-transaction dmls
type CacheInvalidator interface {
	Delete(key string)
}

// Helper method for conn pools to convert errors
func getOrPanic(pool *dbconnpool.ConnectionPool) dbconnpool.PoolConnection {
	conn, err := pool.Get(0)
	if err == nil {
		return conn
	}
	if err == dbconnpool.CONN_POOL_CLOSED_ERR {
		panic(connPoolClosedErr)
	}
	panic(NewTabletErrorSql(FATAL, err))
}

// NewQueryEngine creates a new QueryEngine.
// This is a singleton class.
// You must call this only once.
func NewQueryEngine(config Config) *QueryEngine {
	qe := &QueryEngine{}
	qe.schemaInfo = NewSchemaInfo(
		config.QueryCacheSize,
		time.Duration(config.SchemaReloadTime*1e9),
		time.Duration(config.IdleTimeout*1e9),
	)

	mysqlStats = stats.NewTimings("Mysql")

	// Pools
	qe.cachePool = NewCachePool(
		"Rowcache",
		config.RowCache,
		time.Duration(config.QueryTimeout*1e9),
		time.Duration(config.IdleTimeout*1e9),
	)
	qe.connPool = dbconnpool.NewConnectionPool(
		"ConnPool",
		config.PoolSize,
		time.Duration(config.IdleTimeout*1e9),
	)
	qe.streamConnPool = dbconnpool.NewConnectionPool(
		"StreamConnPool",
		config.StreamPoolSize,
		time.Duration(config.IdleTimeout*1e9),
	)

	// Services
	qe.txPool = NewTxPool(
		"TransactionPool",
		config.TransactionCap,
		time.Duration(config.TransactionTimeout*1e9),
		time.Duration(config.TxPoolTimeout*1e9),
		time.Duration(config.IdleTimeout*1e9),
	)
	qe.connKiller = NewConnectionKiller(1, time.Duration(config.IdleTimeout*1e9))
	qe.consolidator = NewConsolidator()
	qe.invalidator = NewRowcacheInvalidator(qe)
	qe.streamQList = NewQueryList(qe.connKiller)

	// Vars
	qe.queryTimeout.Set(time.Duration(config.QueryTimeout * 1e9))
	qe.spotCheckFreq = sync2.AtomicInt64(config.SpotCheckRatio * spotCheckMultiplier)
	if config.StrictMode {
		qe.strictMode.Set(1)
	}
	qe.strictTableAcl = config.StrictTableAcl
	qe.maxResultSize = sync2.AtomicInt64(config.MaxResultSize)
	qe.maxDMLRows = sync2.AtomicInt64(config.MaxDMLRows)
	qe.streamBufferSize = sync2.AtomicInt64(config.StreamBufferSize)

	// loggers
	qe.accessCheckerLogger = logutil.NewThrottledLogger("accessChecker", 1*time.Second)

	// Stats
	stats.Publish("MaxResultSize", stats.IntFunc(qe.maxResultSize.Get))
	stats.Publish("MaxDMLRows", stats.IntFunc(qe.maxDMLRows.Get))
	stats.Publish("StreamBufferSize", stats.IntFunc(qe.streamBufferSize.Get))
	stats.Publish("QueryTimeout", stats.DurationFunc(qe.queryTimeout.Get))
	queryStats = stats.NewTimings("Queries")
	QPSRates = stats.NewRates("QPS", queryStats, 15, 60*time.Second)
	waitStats = stats.NewTimings("Waits")
	killStats = stats.NewCounters("Kills")
	infoErrors = stats.NewCounters("InfoErrors")
	errorStats = stats.NewCounters("Errors")
	internalErrors = stats.NewCounters("InternalErrors")
	resultStats = stats.NewHistogram("Results", resultBuckets)
	stats.Publish("RowcacheSpotCheckRatio", stats.FloatFunc(func() float64 {
		return float64(qe.spotCheckFreq.Get()) / spotCheckMultiplier
	}))
	spotCheckCount = stats.NewInt("RowcacheSpotCheckCount")

	return qe
}

// Open must be called before sending requests to QueryEngine.
func (qe *QueryEngine) Open(dbconfigs *dbconfigs.DBConfigs, schemaOverrides []SchemaOverride, qrs *QueryRules, mysqld *mysqlctl.Mysqld) {
	qe.dbconfigs = dbconfigs
	connFactory := dbconnpool.DBConnectionCreator(&dbconfigs.App.ConnectionParams, mysqlStats)
	// Create dba params based on App connection params
	// and Dba credentials.
	dba := dbconfigs.App.ConnectionParams
	if dbconfigs.Dba.Uname != "" {
		dba.Uname = dbconfigs.Dba.Uname
		dba.Pass = dbconfigs.Dba.Pass
	}
	dbaConnFactory := dbconnpool.DBConnectionCreator(&dba, mysqlStats)

	strictMode := false
	if qe.strictMode.Get() != 0 {
		strictMode = true
	}
	if !strictMode && dbconfigs.App.EnableRowcache {
		panic(NewTabletError(FATAL, "Rowcache cannot be enabled when queryserver-config-strict-mode is false"))
	}
	if dbconfigs.App.EnableRowcache {
		qe.cachePool.Open()
		log.Infof("rowcache is enabled")
	} else {
		// Invalidator should not be enabled if rowcache is not enabled.
		dbconfigs.App.EnableInvalidator = false
		log.Infof("rowcache is not enabled")
	}

	start := time.Now()
	// schemaInfo depends on cachePool. Every table that has a rowcache
	// points to the cachePool.
	qe.schemaInfo.Open(dbaConnFactory, schemaOverrides, qe.cachePool, qrs, strictMode)
	log.Infof("Time taken to load the schema: %v", time.Now().Sub(start))

	// Start the invalidator only after schema is loaded.
	// This will allow qe to find the table info
	// for the invalidation events that will start coming
	// immediately.
	if dbconfigs.App.EnableInvalidator {
		qe.invalidator.Open(dbconfigs.App.DbName, mysqld)
	}
	qe.connPool.Open(connFactory)
	qe.streamConnPool.Open(connFactory)
	qe.txPool.Open(connFactory)
	qe.connKiller.Open(dbaConnFactory)
}

// Launch launches the specified function inside a goroutine.
// If Close or WaitForTxEmpty is called while a goroutine is running,
// QueryEngine will not return until the existing functions have completed.
// This functionality allows us to launch tasks with the assurance that
// the QueryEngine will not be closed underneath us.
func (qe *QueryEngine) Launch(f func()) {
	qe.tasks.Add(1)
	go func() {
		defer func() {
			qe.tasks.Done()
			if x := recover(); x != nil {
				internalErrors.Add("Task", 1)
				log.Errorf("task error: %v", x)
			}
		}()
		f()
	}()
}

// WaitForTxEmpty must be called before calling Close.
// Before calling WaitForTxEmpty, you must ensure that there
// will be no more calls to Begin.
func (qe *QueryEngine) WaitForTxEmpty() {
	qe.txPool.WaitForEmpty()
}

// Close must be called to shut down QueryEngine.
// You must ensure that no more queries will be sent
// before calling Close.
func (qe *QueryEngine) Close() {
	qe.tasks.Wait()
	// Close in reverse order of Open.
	qe.connKiller.Close()
	qe.txPool.Close()
	qe.streamConnPool.Close()
	qe.connPool.Close()
	qe.invalidator.Close()
	qe.schemaInfo.Close()
	qe.cachePool.Close()
	qe.dbconfigs = nil
}
<|endoftext|>