<commit_before>package app

import (
	"io"
	"sync"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/moncho/dry/ui"
	"github.com/nsf/termbox-go"
)

type focusTracker struct {
	mutex sync.Locker
	focus bool
}

func (f *focusTracker) set(b bool) {
	f.mutex.Lock()
	defer f.mutex.Unlock()
	f.focus = b
}

func (f *focusTracker) hasFocus() bool {
	f.mutex.Lock()
	defer f.mutex.Unlock()
	return f.focus
}

//RenderLoop renders dry until it quits
func RenderLoop(dry *Dry, screen *ui.Screen) {
	if ok, _ := dry.Ok(); !ok {
		return
	}

	keyboardQueue, done := ui.EventChannel()
	timestampQueue := time.NewTicker(1 * time.Second)

	viewClosed := make(chan struct{}, 1)
	keyboardQueueForView := make(chan termbox.Event)
	dryOutputChan := dry.OuputChannel()
	statusBar := ui.NewStatusBar(0)

	defer timestampQueue.Stop()
	defer close(done)
	defer close(keyboardQueueForView)
	defer close(viewClosed)

	Render(dry, screen, statusBar)
	//tracks if the main loop has the focus (and responds to events),
	//or if events have to be delegated.
	//creation belongs outside the loop
	focus := &focusTracker{&sync.Mutex{}, true}

	go func(focus *focusTracker) {
		for {
			dryMessage, ok := <-dryOutputChan
			if ok {
				if focus.hasFocus() {
					statusBar.StatusMessage(dryMessage, 10*time.Second)
					if dry.Changed() {
						screen.Clear()
						Render(dry, screen, statusBar)
					} else {
						statusBar.Render()
					}
					screen.Flush()
				}
			} else {
				return
			}
		}
	}(focus)

loop:
	for {
		//Used for refresh-forcing events happening outside dry
		var refresh = false
		select {
		case <-timestampQueue.C:
			if focus.hasFocus() {
				timestamp := time.Now().Format(`15:04:05`)
				screen.RenderLine(0, 0, `<right><white>`+timestamp+`</></right>`)
				screen.Flush()
			}
		case <-viewClosed:
			focus.set(true)
			dry.ShowMainView()
			refresh = true
		case event := <-keyboardQueue:
			switch event.Type {
			case termbox.EventKey:
				if event.Key == termbox.KeyCtrlC { //Ctrl+C breaks the loop (and exit dry) no matter what
					break loop
				}
				if focus.hasFocus() {
					if event.Ch == 'q' || event.Ch == 'Q' {
						break loop
					} else {
						handler := eventHandlerFactory(dry, screen, keyboardQueueForView, viewClosed)
						if handler != nil {
							r, f := handler.handle(event)
							refresh = r
							focus.set(f)
						} else {
							log.Panic("There is no event handler")
						}
					}
				} else {
					//Whoever has the focus, handles the event
					keyboardQueueForView <- event
				}
			case termbox.EventResize:
				screen.Resize()
				refresh = true
			}
		}
		if focus.hasFocus() && refresh {
			screen.Clear()
			Render(dry, screen, statusBar)
		}
	}

	log.Debug("something broke the loop. Time to die")
}

func stream(screen *ui.Screen, stream io.ReadCloser, keyboardQueue chan termbox.Event, done chan<- struct{}) {
	screen.Clear()
	screen.Sync()
	v := ui.NewLess()
	go func() {
		io.Copy(v, stream)
	}()
	if err := v.Focus(keyboardQueue); err != nil {
		ui.ShowErrorMessage(screen, keyboardQueue, err)
	}
	stream.Close()
	termbox.HideCursor()
	screen.Clear()
	screen.Sync()
	done <- struct{}{}
}

//autorefresh view that autorefreshes its content every second
func autorefresh(dry *Dry, screen *ui.Screen, keyboardQueue chan termbox.Event, done chan<- struct{}, doneStats chan<- bool, errC <-chan error) {
	screen.Clear()
	v := ui.NewMarkupView("", 0, 0, screen.Width, screen.Height, false)
	//used to coordinate rendering between the ticker
	//and the exit event
	var mutex = &sync.Mutex{}
	Write(dry, v)
	err := v.Render()
	if err != nil {
		ui.ShowErrorMessage(screen, keyboardQueue, err)
	}
	screen.Flush()
	//the ticker is created after the first render
	timestampQueue := time.NewTicker(1000 * time.Millisecond)

loop:
	for {
		select {
		case <-errC:
			{
				mutex.Lock()
				timestampQueue.Stop()
				break loop
			}
		case event := <-keyboardQueue:
			switch event.Type {
			case termbox.EventKey:
				if event.Key == termbox.KeyEsc {
					//the lock is acquired and the time-based refresh queue is stopped
					//before breaking the loop
					mutex.Lock()
					timestampQueue.Stop()
					break loop
				}
			}
		case <-timestampQueue.C:
			{
				mutex.Lock()
				v.Clear()
				Write(dry, v)
				v.Render()
				screen.Flush()
				mutex.Unlock()
			}
		}
	}
	//cleanup before exiting, the screen is cleared and the lock released
	termbox.HideCursor()
	screen.Clear()
	screen.Sync()
	mutex.Unlock()
	doneStats <- true
	done <- struct{}{}
}

//less shows dry output in a "less" emulator
func less(dry *Dry, screen *ui.Screen, keyboardQueue chan termbox.Event, done chan struct{}) {
	screen.Clear()
	v := ui.NewLess()
	v.MarkupSupport()
	go Write(dry, v)
	//Focus blocks until v decides that it does not want focus any more
	if err := v.Focus(keyboardQueue); err != nil {
		ui.ShowErrorMessage(screen, keyboardQueue, err)
	}
	termbox.HideCursor()
	screen.Clear()
	screen.Sync()

	done <- struct{}{}
}
<commit_msg>Render dry every time a message is received on the render channel<commit_after>package app

import (
	"io"
	"sync"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/moncho/dry/ui"
	"github.com/nsf/termbox-go"
)

type focusTracker struct {
	mutex sync.Locker
	focus bool
}

func (f *focusTracker) set(b bool) {
	f.mutex.Lock()
	defer f.mutex.Unlock()
	f.focus = b
}

func (f *focusTracker) hasFocus() bool {
	f.mutex.Lock()
	defer f.mutex.Unlock()
	return f.focus
}

//RenderLoop renders dry until it quits
func RenderLoop(dry *Dry, screen *ui.Screen) {
	if ok, _ := dry.Ok(); !ok {
		return
	}

	keyboardQueue, done := ui.EventChannel()
	timestampQueue := time.NewTicker(1 * time.Second)

	viewClosed := make(chan struct{}, 1)
	renderChan := make(chan struct{})

	keyboardQueueForView := make(chan termbox.Event)
	dryOutputChan := dry.OuputChannel()
	statusBar := ui.NewStatusBar(0)

	defer timestampQueue.Stop()
	defer close(done)
	defer close(keyboardQueueForView)
	defer close(viewClosed)
	defer close(renderChan)

	//rendes dry on message
	go func() {
		for {
			_, stillOpen := <-renderChan
			if stillOpen {
				screen.Clear()
				Render(dry, screen, statusBar)
			} else {
				return
			}
		}
	}()

	renderChan <- struct{}{}

	//tracks if the main loop has the focus (and responds to events),
	//or if events have to be delegated.
	//creation belongs outside the loop
	focus := &focusTracker{&sync.Mutex{}, true}

	go func(focus *focusTracker) {
		for {
			dryMessage, ok := <-dryOutputChan
			if ok {
				if focus.hasFocus() {
					statusBar.StatusMessage(dryMessage, 10*time.Second)
					if dry.Changed() {
						renderChan <- struct{}{}
					} else {
						statusBar.Render()
					}
					screen.Flush()
				}
			} else {
				return
			}
		}
	}(focus)

	//loop handles input and timer events until a closing event happens
loop:
	for {
		//Used for refresh-forcing events happening outside dry
		var refresh = false
		select {
		case <-timestampQueue.C:
			if focus.hasFocus() {
				timestamp := time.Now().Format(`15:04:05`)
				screen.RenderLine(0, 0, `<right><white>`+timestamp+`</></right>`)
				screen.Flush()
			}
		case <-viewClosed:
			focus.set(true)
			dry.ShowMainView()
			refresh = true
		case event := <-keyboardQueue:
			switch event.Type {
			case termbox.EventKey:
				if event.Key == termbox.KeyCtrlC { //Ctrl+C breaks the loop (and exits dry) no matter what
					break loop
				}
				if focus.hasFocus() {
					if event.Ch == 'q' || event.Ch == 'Q' {
						break loop
					} else {
						handler := eventHandlerFactory(dry, screen, keyboardQueueForView, viewClosed)
						if handler != nil {
							r, f := handler.handle(event)
							refresh = r
							focus.set(f)
						} else {
							log.Panic("There is no event handler")
						}
					}
				} else {
					//Whoever has the focus, handles the event
					keyboardQueueForView <- event
				}
			case termbox.EventResize:
				screen.Resize()
				refresh = true
			}
		}
		if focus.hasFocus() && refresh {
			renderChan <- struct{}{}
		}
	}

	log.Debug("something broke the loop. Time to die")
}

func stream(screen *ui.Screen, stream io.ReadCloser, keyboardQueue chan termbox.Event, done chan<- struct{}) {
	screen.Clear()
	screen.Sync()
	v := ui.NewLess()
	go func() {
		io.Copy(v, stream)
	}()
	if err := v.Focus(keyboardQueue); err != nil {
		ui.ShowErrorMessage(screen, keyboardQueue, err)
	}
	stream.Close()
	termbox.HideCursor()
	screen.Clear()
	screen.Sync()
	done <- struct{}{}
}

//autorefresh view that autorefreshes its content every second
func autorefresh(dry *Dry, screen *ui.Screen, keyboardQueue chan termbox.Event, done chan<- struct{}, doneStats chan<- bool, errC <-chan error) {
	screen.Clear()
	v := ui.NewMarkupView("", 0, 0, screen.Width, screen.Height, false)
	//used to coordinate rendering between the ticker
	//and the exit event
	var mutex = &sync.Mutex{}
	Write(dry, v)
	err := v.Render()
	if err != nil {
		ui.ShowErrorMessage(screen, keyboardQueue, err)
	}
	screen.Flush()
	//the ticker is created after the first render
	timestampQueue := time.NewTicker(1000 * time.Millisecond)

loop:
	for {
		select {
		case <-errC:
			{
				mutex.Lock()
				timestampQueue.Stop()
				break loop
			}
		case event := <-keyboardQueue:
			switch event.Type {
			case termbox.EventKey:
				if event.Key == termbox.KeyEsc {
					//the lock is acquired and the time-based refresh queue is stopped
					//before breaking the loop
					mutex.Lock()
					timestampQueue.Stop()
					break loop
				}
			}
		case <-timestampQueue.C:
			{
				mutex.Lock()
				v.Clear()
				Write(dry, v)
				v.Render()
				screen.Flush()
				mutex.Unlock()
			}
		}
	}
	//cleanup before exiting, the screen is cleared and the lock released
	termbox.HideCursor()
	screen.Clear()
	screen.Sync()
	mutex.Unlock()
	doneStats <- true
	done <- struct{}{}
}

//less shows dry output in a "less" emulator
func less(dry *Dry, screen *ui.Screen, keyboardQueue chan termbox.Event, done chan struct{}) {
	screen.Clear()
	v := ui.NewLess()
	v.MarkupSupport()
	go Write(dry, v)
	//Focus blocks until v decides that it does not want focus any more
	if err := v.Focus(keyboardQueue); err != nil {
		ui.ShowErrorMessage(screen, keyboardQueue, err)
	}
	termbox.HideCursor()
	screen.Clear()
	screen.Sync()

	done <- struct{}{}
}
<|endoftext|>


<commit_before>package aerospike

import (
	"net"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/influxdata/telegraf"
	"github.com/influxdata/telegraf/internal/errchan"
	"github.com/influxdata/telegraf/plugins/inputs"

	as "github.com/aerospike/aerospike-client-go"
)

type Aerospike struct {
	Servers []string
}

var sampleConfig = `
  ## Aerospike servers to connect to (with port)
  ## This plugin will query all namespaces the aerospike
  ## server has configured and get stats for them.
  servers = ["localhost:3000"]
 `

func (a *Aerospike) SampleConfig() string {
	return sampleConfig
}

func (a *Aerospike) Description() string {
	return "Read stats from aerospike server(s)"
}

func (a *Aerospike) Gather(acc telegraf.Accumulator) error {
	if len(a.Servers) == 0 {
		return a.gatherServer("127.0.0.1:3000", acc)
	}

	var wg sync.WaitGroup
	errChan := errchan.New(len(a.Servers))
	wg.Add(len(a.Servers))
	for _, server := range a.Servers {
		go func(serv string) {
			defer wg.Done()
			errChan.C <- a.gatherServer(serv, acc)
		}(server)
	}

	wg.Wait()
	return errChan.Error()
}

func (a *Aerospike) gatherServer(hostport string, acc telegraf.Accumulator) error {
	host, port, err := net.SplitHostPort(hostport)
	if err != nil {
		return err
	}

	iport, err := strconv.Atoi(port)
	if err != nil {
		iport = 3000
	}

	c, err := as.NewClient(host, iport)
	if err != nil {
		return err
	}
	defer c.Close()

	nodes := c.GetNodes()
	for _, n := range nodes {
		tags := map[string]string{
			"aerospike_host": hostport,
		}
		fields := map[string]interface{}{
			"node_name": n.GetName(),
		}
		stats, err := as.RequestNodeStats(n)
		if err != nil {
			return err
		}
		for k, v := range stats {
			fields[strings.Replace(k, "-", "_", -1)] = parseValue(v)
		}
		acc.AddFields("aerospike_node", fields, tags, time.Now())

		info, err := as.RequestNodeInfo(n, "namespaces")
		if err != nil {
			return err
		}
		namespaces := strings.Split(info["namespaces"], ";")

		for _, namespace := range namespaces {
			nTags := map[string]string{
				"aerospike_host": hostport,
			}
			nTags["namespace"] = namespace
			nFields := map[string]interface{}{
				"node_name": n.GetName(),
			}
			info, err := as.RequestNodeInfo(n, "namespace/"+namespace)
			if err != nil {
				continue
			}
			stats := strings.Split(info["namespace/"+namespace], ";")
			for _, stat := range stats {
				parts := strings.Split(stat, "=")
				if len(parts) < 2 {
					continue
				}
				nFields[strings.Replace(parts[0], "-", "_", -1)] = parseValue(parts[1])
			}
			acc.AddFields("aerospike_namespace", nFields, nTags, time.Now())
		}
	}
	return nil
}

func parseValue(v string) interface{} {
	if parsed, err := strconv.ParseInt(v, 10, 64); err == nil {
		return parsed
	} else if parsed, err := strconv.ParseUint(v, 10, 64); err == nil {
		return -int64(parsed)
	} else if parsed, err := strconv.ParseBool(v); err == nil {
		return parsed
	} else {
		return v
	}
}

func copyTags(m map[string]string) map[string]string {
	out := make(map[string]string)
	for k, v := range m {
		out[k] = v
	}
	return out
}

func init() {
	inputs.Add("aerospike", func() telegraf.Input {
		return &Aerospike{}
	})
}
<commit_msg>skip values with overflow<commit_after>package aerospike

import (
	"errors"
	"log"
	"net"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/influxdata/telegraf"
	"github.com/influxdata/telegraf/internal/errchan"
	"github.com/influxdata/telegraf/plugins/inputs"

	as "github.com/aerospike/aerospike-client-go"
)

type Aerospike struct {
	Servers []string
}

var sampleConfig = `
  ## Aerospike servers to connect to (with port)
  ## This plugin will query all namespaces the aerospike
  ## server has configured and get stats for them.
  servers = ["localhost:3000"]
 `

func (a *Aerospike) SampleConfig() string {
	return sampleConfig
}

func (a *Aerospike) Description() string {
	return "Read stats from aerospike server(s)"
}

func (a *Aerospike) Gather(acc telegraf.Accumulator) error {
	if len(a.Servers) == 0 {
		return a.gatherServer("127.0.0.1:3000", acc)
	}

	var wg sync.WaitGroup
	errChan := errchan.New(len(a.Servers))
	wg.Add(len(a.Servers))
	for _, server := range a.Servers {
		go func(serv string) {
			defer wg.Done()
			errChan.C <- a.gatherServer(serv, acc)
		}(server)
	}

	wg.Wait()
	return errChan.Error()
}

func (a *Aerospike) gatherServer(hostport string, acc telegraf.Accumulator) error {
	host, port, err := net.SplitHostPort(hostport)
	if err != nil {
		return err
	}

	iport, err := strconv.Atoi(port)
	if err != nil {
		iport = 3000
	}

	c, err := as.NewClient(host, iport)
	if err != nil {
		return err
	}
	defer c.Close()

	nodes := c.GetNodes()
	for _, n := range nodes {
		tags := map[string]string{
			"aerospike_host": hostport,
		}
		fields := map[string]interface{}{
			"node_name": n.GetName(),
		}
		stats, err := as.RequestNodeStats(n)
		if err != nil {
			return err
		}
		for k, v := range stats {
			val, err := parseValue(v)
			if err == nil {
				fields[strings.Replace(k, "-", "_", -1)] = val
			} else {
				log.Printf("skipping aerospike field %v with int64 overflow", k)
			}
		}
		acc.AddFields("aerospike_node", fields, tags, time.Now())

		info, err := as.RequestNodeInfo(n, "namespaces")
		if err != nil {
			return err
		}
		namespaces := strings.Split(info["namespaces"], ";")

		for _, namespace := range namespaces {
			nTags := map[string]string{
				"aerospike_host": hostport,
			}
			nTags["namespace"] = namespace
			nFields := map[string]interface{}{
				"node_name": n.GetName(),
			}
			info, err := as.RequestNodeInfo(n, "namespace/"+namespace)
			if err != nil {
				continue
			}
			stats := strings.Split(info["namespace/"+namespace], ";")
			for _, stat := range stats {
				parts := strings.Split(stat, "=")
				if len(parts) < 2 {
					continue
				}
				val, err := parseValue(parts[1])
				if err == nil {
					nFields[strings.Replace(parts[0], "-", "_", -1)] = val
				} else {
					log.Printf("skipping aerospike field %v with int64 overflow", parts[0])
				}
			}
			acc.AddFields("aerospike_namespace", nFields, nTags, time.Now())
		}
	}
	return nil
}

func parseValue(v string) (interface{}, error) {
	if parsed, err := strconv.ParseInt(v, 10, 64); err == nil {
		return parsed, nil
	} else if _, err := strconv.ParseUint(v, 10, 64); err == nil {
		// int64 overflow, yet valid uint64
		return nil, errors.New("Number is too large")
	} else if parsed, err := strconv.ParseBool(v); err == nil {
		return parsed, nil
	} else {
		return v, nil
	}
}

func copyTags(m map[string]string) map[string]string {
	out := make(map[string]string)
	for k, v := range m {
		out[k] = v
	}
	return out
}

func init() {
	inputs.Add("aerospike", func() telegraf.Input {
		return &Aerospike{}
	})
}
<|endoftext|>


<commit_before>package async

import (
	"context"
	"fmt"
	"sync"
	"time"
)

var (
	input    chan *cmd
	output   chan *batchCmd
	groupDic map[string]*group
	gLocker  sync.RWMutex
)

type CacheProvider interface {
	Put(string, interface{}, interface{}) error
	Get(string, interface{}) (interface{}, error)
}

func init() {
	groupDic = make(map[string]*group)
	input = make(chan *cmd, 128)
	output = make(chan *batchCmd, 128)
	go runloop()
}

type group struct {
	name      string
	batchSize int
	method    func(...interface{}) (map[interface{}]interface{}, error)
	cmdDic    map[interface{}][]*cmd
	keyDic    map[interface{}]bool
	cache     CacheProvider
}

type cmd struct {
	group    string
	key      interface{}
	callback chan interface{}
}

type batchCmd struct {
	group  string
	keys   []interface{}
	err    error
	result map[interface{}]interface{}
}

func RegisterGroup(
	name string,
	batchSize int,
	method func(...interface{}) (map[interface{}]interface{}, error),
	cache CacheProvider) error {
	gLocker.Lock()
	defer gLocker.Unlock()
	_, ok := groupDic[name]
	if ok {
		return fmt.Errorf("duplicate group:%s", name)
	}
	groupDic[name] = &group{
		name:      name,
		batchSize: batchSize,
		method:    method,
		cmdDic:    make(map[interface{}][]*cmd),
		keyDic:    make(map[interface{}]bool),
		cache:     cache,
	}
	return nil
}

func doing(ctx context.Context, b *batchCmd, method func(...interface{}) (map[interface{}]interface{}, error)) {
	res, err := Safety(func() (interface{}, error) {
		return method(b.keys...)
	})
	if err != nil {
		b.err = err
	} else {
		b.result = res.(map[interface{}]interface{})
	}
	output <- b
}

func runloop() {
	ctx := context.Background()
	timer := time.NewTicker(10 * time.Millisecond)
	for {
		select {
		case c := <-input:
			{
				gLocker.RLocker()
				defer gLocker.RUnlock()
				g, ok := groupDic[c.group]
				if false == ok {
					c.callback <- fmt.Errorf("invalid group:%s", c.group)
					close(c.callback)
					continue
				}
				// cache provider
				if g.cache != nil {
					res, err := g.cache.Get(g.name, c.key)
					if res != nil && err == nil {
						c.callback <- res
						close(c.callback)
						continue
					}
				}
				target, ok := g.cmdDic[c.key]
				if ok {
					g.cmdDic[c.key] = append(target, c)
				} else {
					g.cmdDic[c.key] = []*cmd{c}
					g.keyDic[c.key] = true
				}

				if len(g.keyDic) >= g.batchSize {
					b := &batchCmd{group: g.name}
					b.keys = make([]interface{}, len(g.keyDic))
					index := 0
					for k, _ := range g.keyDic {
						b.keys[index] = k
						index = index + 1
					}
					g.keyDic = nil
					g.keyDic = make(map[interface{}]bool)
					go doing(ctx, b, g.method)
				}
			}
		case b := <-output:
			{
				gLocker.RLocker()
				defer gLocker.RUnlock()
				g, _ := groupDic[b.group]
				if b.err != nil {
					for _, key := range b.keys {
						target, ok := g.cmdDic[key]
						if ok {
							for index, _ := range target {
								c := target[index]
								c.callback <- b.err
								close(c.callback)
							}
						}
						delete(g.cmdDic, key)
					}
				} else {
					for _, key := range b.keys {
						res, ok := b.result[key]
						if false == ok {
							res = fmt.Errorf("invalid key:%s", key)
						} else {
							// cache provider
							if g.cache != nil {
								g.cache.Put(g.name, key, res)
							}
						}
						target, ok := g.cmdDic[key]
						if ok {
							for index, _ := range target {
								c := target[index]
								c.callback <- res
								close(c.callback)
							}
						}
						delete(g.cmdDic, key)
					}
				}
			}
		case <-timer.C:
			{
				gLocker.RLocker()
				defer gLocker.RUnlock()
				for _, g := range groupDic {
					if len(g.keyDic) > 0 {
						b := &batchCmd{group: g.name}
						b.keys = make([]interface{}, len(g.keyDic))
						index := 0
						for k, _ := range g.keyDic {
							b.keys[index] = k
							index = index + 1
						}
						g.keyDic = make(map[interface{}]bool)
						go doing(ctx, b, g.method)
					}
				}
				timer.Reset(10 * time.Millisecond)
			}
		}
	}
}

func Get(group string, key interface{}) (interface{}, error) {
	c := &cmd{
		group:    group,
		key:      key,
		callback: make(chan interface{}, 1),
	}
	input <- c
	res := <-c.callback
	switch res.(type) {
	case error:
		return nil, res.(error)
	default:
		return res, nil
	}
}
<commit_msg>update code<commit_after>package async

import (
	"context"
	"fmt"
	"sync"
	"time"
)

var (
	input    chan *cmd
	output   chan *batchCmd
	groupDic map[string]*group
	gLocker  sync.RWMutex
)

type CacheProvider interface {
	Put(string, interface{}, interface{}) error
	Get(string, interface{}) (interface{}, error)
}

func init() {
	groupDic = make(map[string]*group)
	input = make(chan *cmd, 128)
	output = make(chan *batchCmd, 128)
	go runloop()
}

type group struct {
	name      string
	batchSize int
	method    func(...interface{}) (map[interface{}]interface{}, error)
	cmdDic    map[interface{}][]*cmd
	keyDic    map[interface{}]bool
	cache     CacheProvider
}

type cmd struct {
	group    string
	key      interface{}
	callback chan interface{}
}

type batchCmd struct {
	group  string
	keys   []interface{}
	err    error
	result map[interface{}]interface{}
}

func RegisterGroup(
	name string,
	batchSize int,
	method func(...interface{}) (map[interface{}]interface{}, error),
	cache CacheProvider) error {
	gLocker.Lock()
	defer gLocker.Unlock()
	_, ok := groupDic[name]
	if ok {
		return fmt.Errorf("duplicate group:%s", name)
	}
	groupDic[name] = &group{
		name:      name,
		batchSize: batchSize,
		method:    method,
		cmdDic:    make(map[interface{}][]*cmd),
		keyDic:    make(map[interface{}]bool),
		cache:     cache,
	}
	return nil
}

func doing(ctx context.Context, b *batchCmd, method func(...interface{}) (map[interface{}]interface{}, error)) {
	res, err := Safety(func() (interface{}, error) {
		return method(b.keys...)
	})
	if err != nil {
		b.err = err
	} else {
		b.result = res.(map[interface{}]interface{})
	}
	output <- b
}

func runloop() {
	ctx := context.Background()
	timer := time.NewTicker(10 * time.Millisecond)
	for {
		select {
		case c := <-input:
			{
				gLocker.RLocker()
				defer gLocker.RUnlock()
				g, ok := groupDic[c.group]
				if false == ok {
					c.callback <- fmt.Errorf("invalid group:%s", c.group)
					close(c.callback)
					continue
				}
				// cache provider
				if g.cache != nil {
					res, err := g.cache.Get(g.name, c.key)
					if res != nil && err == nil {
						c.callback <- res
						close(c.callback)
						continue
					}
				}
				target, ok := g.cmdDic[c.key]
				if ok {
					g.cmdDic[c.key] = append(target, c)
				} else {
					g.cmdDic[c.key] = []*cmd{c}
					g.keyDic[c.key] = true
				}

				if len(g.keyDic) >= g.batchSize {
					b := &batchCmd{group: g.name}
					b.keys = make([]interface{}, len(g.keyDic))
					index := 0
					for k, _ := range g.keyDic {
						b.keys[index] = k
						index = index + 1
					}
					g.keyDic = nil
					g.keyDic = make(map[interface{}]bool)
					go doing(ctx, b, g.method)
				}
			}
		case b := <-output:
			{
				gLocker.RLocker()
				defer gLocker.RUnlock()
				g, _ := groupDic[b.group]
				if b.err != nil {
					for _, key := range b.keys {
						target, ok := g.cmdDic[key]
						if ok {
							for index, _ := range target {
								c := target[index]
								c.callback <- b.err
								close(c.callback)
							}
						}
						delete(g.cmdDic, key)
					}
				} else {
					for _, key := range b.keys {
						res, ok := b.result[key]
						if false == ok {
							res = fmt.Errorf("invalid key:%s", key)
						} else {
							// cache provider
							if g.cache != nil {
								g.cache.Put(g.name, key, res)
							}
						}
						target, ok := g.cmdDic[key]
						if ok {
							for index, _ := range target {
								c := target[index]
								c.callback <- res
								close(c.callback)
							}
						}
						delete(g.cmdDic, key)
					}
				}
			}
		case <-timer.C:
			{
				gLocker.RLocker()
				defer gLocker.RUnlock()
				for _, g := range groupDic {
					if len(g.keyDic) > 0 {
						b := &batchCmd{group: g.name}
						b.keys = make([]interface{}, len(g.keyDic))
						index := 0
						for k, _ := range g.keyDic {
							b.keys[index] = k
							index = index + 1
						}
						g.keyDic = nil
						g.keyDic = make(map[interface{}]bool)
						go doing(ctx, b, g.method)
					}
				}
				timer.Reset(10 * time.Millisecond)
			}
		}
	}
}

func Get(group string, key interface{}) (interface{}, error) {
	c := &cmd{
		group:    group,
		key:      key,
		callback: make(chan interface{}, 1),
	}
	input <- c
	res := <-c.callback
	switch res.(type) {
	case error:
		return nil, res.(error)
	default:
		return res, nil
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"github.com/APTrust/bagman/bagman"
	"github.com/APTrust/bagman/partner-apps"
	"os"
)

var configFile string
var checksum string
var showHelp bool
var deleteFiles bool

func main() {
	parseCommandLine()
 	client, err := bagman.NewPartnerS3ClientFromConfigFile(configFile, false)
	if err != nil {
		fmt.Printf("[FATAL] %v\n", err)
		return
	}
	fetchAll(client)
}

func fetchAll(client *bagman.PartnerS3Client) {
	succeeded := 0
	failed := 0
	files := flag.Args()
	bucketName := client.PartnerConfig.RestorationBucket
	fmt.Printf("Downloading %d files to %s\n", len(files), client.PartnerConfig.DownloadDir)
	for _, file := range files {
		digest, err := client.DownloadFile(bucketName, file, checksum)
		if err != nil {
			fmt.Printf("[ERROR] Failed to download %s: %v\n", file, err)
			failed++
			continue
		}
		deleteMessage := ""
		if deleteFiles {
			err = client.Delete(bucketName, file)
			if err != nil {
				deleteMessage = fmt.Sprintf("File could not be deleted from S3 " +
					"restoration bucket after download: %v", err)
			} else {
				deleteMessage = "File was deleted from S3 restoration bucket."
			}
		}
		if checksum == "none" {
			fmt.Printf("[OK]    Downloaded %s. %s\n", file, deleteMessage)
		} else {
			fmt.Printf("[OK]    Downloaded %s with %s: %s. %s\n", file, checksum, digest, deleteMessage)
		}
		succeeded++
	}
	fmt.Printf("Finished. %d succeeded, %d failed\n", succeeded, failed)
}

func parseCommandLine() {
	showVersion := false
	flag.BoolVar(&showVersion, "version", false, "Print version and exit")
	flag.BoolVar(&showHelp, "h", false, "Show help")
	flag.BoolVar(&deleteFiles, "delete", false, "Delete files from restoration bucket after download")
	flag.StringVar(&configFile, "config", "", "APTrust config file")
	flag.StringVar(&checksum, "checksum", "", "Checksum to calculate on download (md5 or sha256). Default is none.")
	flag.Parse()
	if showVersion {
		partnerapps.PrintVersion("apt_download")
		os.Exit(0)
	}
	if showHelp || configFile == "" {
		partnerapps.PrintVersion("apt_download")
		printUsage()
		os.Exit(0)
	}
	if len(os.Args) < 2 {
		fmt.Printf("Please specify one or more files to download. ")
		fmt.Printf("Or use apt_upload -h for help.\n")
		os.Exit(1)
	}
	if checksum != "" && checksum != "md5" && checksum != "sha256" && checksum != "none" {
		fmt.Printf("checksum must be md5, sha256 or none. Default is none.")
		os.Exit(1)
	}
	if checksum == "" {
		checksum = "none"
	}
}

func printUsage() {
	message := `
apt_download [--checksum=<md5|sha256>] [--delete] --config=pathToConfigFile <file1>...<fileN>

Downloads APTrust bag files from the S3 restoration bucket.
You must first request bag restoration through the APTrust Web UI.
Once you are notified that the bag has been restored, you can
download it with apt_download.

The checksum param is optional. If omitted, no checksum digest will
be calculated on the downloaded file. Valid checksum options are:

md5       Calculates the md5 digest
sha256    Calculated the sha256 digest
none      Does not calculate any digest. This is the default, and
          this will be applied if you omit the -checksum flag.

If you supply the --delete flag, files will be deleted from the S3
restoration bucket after download.

apt_download prints all output to stdout. Typical output includes the
result of the file download (OK or ERROR) and the md5 or sha256 checksum,
if you requested that on the command line.

Output looks like this:

Downloading 2 files to /home/josie/downloads
[OK]    Downloaded archive1.tar with md5: 845f9be9c825b668f3bae1d23ceb01de
[OK]    Downloaded archive2.tar with md5: 3d4fede4b748a5d8acbdefd13f39d0cd
Finished. 2 succeeded, 0 failed
`
	fmt.Println(message)
	fmt.Println(partnerapps.ConfigHelp)
}
<commit_msg>Remove period from end of checksum digest<commit_after>package main

import (
	"flag"
	"fmt"
	"github.com/APTrust/bagman/bagman"
	"github.com/APTrust/bagman/partner-apps"
	"os"
)

var configFile string
var checksum string
var showHelp bool
var deleteFiles bool

func main() {
	parseCommandLine()
 	client, err := bagman.NewPartnerS3ClientFromConfigFile(configFile, false)
	if err != nil {
		fmt.Printf("[FATAL] %v\n", err)
		return
	}
	fetchAll(client)
}

func fetchAll(client *bagman.PartnerS3Client) {
	succeeded := 0
	failed := 0
	files := flag.Args()
	bucketName := client.PartnerConfig.RestorationBucket
	fmt.Printf("Downloading %d files to %s\n", len(files), client.PartnerConfig.DownloadDir)
	for _, file := range files {
		digest, err := client.DownloadFile(bucketName, file, checksum)
		if err != nil {
			fmt.Printf("[ERROR] Failed to download %s: %v\n", file, err)
			failed++
			continue
		}
		deleteMessage := ""
		if deleteFiles {
			err = client.Delete(bucketName, file)
			if err != nil {
				deleteMessage = fmt.Sprintf("File could not be deleted from S3 " +
					"restoration bucket after download: %v", err)
			} else {
				deleteMessage = "File was deleted from S3 restoration bucket."
			}
		}
		if checksum == "none" {
			fmt.Printf("[OK]    Downloaded %s. %s\n", file, deleteMessage)
		} else {
			fmt.Printf("[OK]    Downloaded %s with %s: %s %s\n", file, checksum, digest, deleteMessage)
		}
		succeeded++
	}
	fmt.Printf("Finished. %d succeeded, %d failed\n", succeeded, failed)
}

func parseCommandLine() {
	showVersion := false
	flag.BoolVar(&showVersion, "version", false, "Print version and exit")
	flag.BoolVar(&showHelp, "h", false, "Show help")
	flag.BoolVar(&deleteFiles, "delete", false, "Delete files from restoration bucket after download")
	flag.StringVar(&configFile, "config", "", "APTrust config file")
	flag.StringVar(&checksum, "checksum", "", "Checksum to calculate on download (md5 or sha256). Default is none.")
	flag.Parse()
	if showVersion {
		partnerapps.PrintVersion("apt_download")
		os.Exit(0)
	}
	if showHelp || configFile == "" {
		partnerapps.PrintVersion("apt_download")
		printUsage()
		os.Exit(0)
	}
	if len(os.Args) < 2 {
		fmt.Printf("Please specify one or more files to download. ")
		fmt.Printf("Or use apt_upload -h for help.\n")
		os.Exit(1)
	}
	if checksum != "" && checksum != "md5" && checksum != "sha256" && checksum != "none" {
		fmt.Printf("checksum must be md5, sha256 or none. Default is none.")
		os.Exit(1)
	}
	if checksum == "" {
		checksum = "none"
	}
}

func printUsage() {
	message := `
apt_download [--checksum=<md5|sha256>] [--delete] --config=pathToConfigFile <file1>...<fileN>

Downloads APTrust bag files from the S3 restoration bucket.
You must first request bag restoration through the APTrust Web UI.
Once you are notified that the bag has been restored, you can
download it with apt_download.

The checksum param is optional. If omitted, no checksum digest will
be calculated on the downloaded file. Valid checksum options are:

md5       Calculates the md5 digest
sha256    Calculated the sha256 digest
none      Does not calculate any digest. This is the default, and
          this will be applied if you omit the -checksum flag.

If you supply the --delete flag, files will be deleted from the S3
restoration bucket after download.

apt_download prints all output to stdout. Typical output includes the
result of the file download (OK or ERROR) and the md5 or sha256 checksum,
if you requested that on the command line.

Output looks like this:

Downloading 2 files to /home/josie/downloads
[OK]    Downloaded archive1.tar with md5: 845f9be9c825b668f3bae1d23ceb01de
[OK]    Downloaded archive2.tar with md5: 3d4fede4b748a5d8acbdefd13f39d0cd
Finished. 2 succeeded, 0 failed
`
	fmt.Println(message)
	fmt.Println(partnerapps.ConfigHelp)
}
<|endoftext|>


<commit_before>package object

import (
	"gopkg.in/src-d/go-git.v4/plumbing"

	. "gopkg.in/check.v1"
)

type CommitWalkerSuite struct {
	BaseObjectsSuite
}

var _ = Suite(&CommitWalkerSuite{})

func (s *CommitWalkerSuite) TestCommitPreIterator(c *C) {
	commit := s.commit(c, s.Fixture.Head)

	var commits []*Commit
	NewCommitPreorderIter(commit, nil, nil).ForEach(func(c *Commit) error {
		commits = append(commits, c)
		return nil
	})

	c.Assert(commits, HasLen, 8)

	expected := []string{
		"6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
		"918c48b83bd081e863dbe1b80f8998f058cd8294",
		"af2d6a6954d532f8ffb47615169c8fdf9d383a1a",
		"1669dce138d9b841a518c64b10914d88f5e488ea",
		"35e85108805c84807bc66a02d91535e1e24b38b9",
		"b029517f6300c2da0f4b651b8642506cd6aaf45d",
		"a5b8b09e2f8fcb0bb99d3ccb0958157b40890d69",
		"b8e471f58bcbca63b07bda20e428190409c2db47",
	}
	for i, commit := range commits {
		c.Assert(commit.Hash.String(), Equals, expected[i])
	}
}

func (s *CommitWalkerSuite) TestCommitPreIteratorWithIgnore(c *C) {
	commit := s.commit(c, s.Fixture.Head)

	var commits []*Commit
	NewCommitPreorderIter(commit, nil, []plumbing.Hash{
		plumbing.NewHash("af2d6a6954d532f8ffb47615169c8fdf9d383a1a"),
	}).ForEach(func(c *Commit) error {
		commits = append(commits, c)
		return nil
	})

	c.Assert(commits, HasLen, 2)

	expected := []string{
		"6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
		"918c48b83bd081e863dbe1b80f8998f058cd8294",
	}
	for i, commit := range commits {
		c.Assert(commit.Hash.String(), Equals, expected[i])
	}
}

func (s *CommitWalkerSuite) TestCommitPreIteratorWithSeenExternal(c *C) {
	commit := s.commit(c, s.Fixture.Head)

	var commits []*Commit
	seenExternal := map[plumbing.Hash]bool{
		plumbing.NewHash("af2d6a6954d532f8ffb47615169c8fdf9d383a1a"): true,
	}
	NewCommitPreorderIter(commit, seenExternal, nil).
		ForEach(func(c *Commit) error {
			commits = append(commits, c)
			return nil
		})

	c.Assert(commits, HasLen, 2)

	expected := []string{
		"6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
		"918c48b83bd081e863dbe1b80f8998f058cd8294",
	}
	for i, commit := range commits {
		c.Assert(commit.Hash.String(), Equals, expected[i])
	}
}

func (s *CommitWalkerSuite) TestCommitPostIterator(c *C) {
	commit := s.commit(c, s.Fixture.Head)

	var commits []*Commit
	NewCommitPostorderIter(commit, nil).ForEach(func(c *Commit) error {
		commits = append(commits, c)
		return nil
	})

	c.Assert(commits, HasLen, 8)

	expected := []string{
		"6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
		"918c48b83bd081e863dbe1b80f8998f058cd8294",
		"af2d6a6954d532f8ffb47615169c8fdf9d383a1a",
		"1669dce138d9b841a518c64b10914d88f5e488ea",
		"a5b8b09e2f8fcb0bb99d3ccb0958157b40890d69",
		"b8e471f58bcbca63b07bda20e428190409c2db47",
		"b029517f6300c2da0f4b651b8642506cd6aaf45d",
		"35e85108805c84807bc66a02d91535e1e24b38b9",
	}

	for i, commit := range commits {
		c.Assert(commit.Hash.String(), Equals, expected[i])
	}
}

func (s *CommitWalkerSuite) TestCommitPostIteratorWithIgnore(c *C) {
	commit := s.commit(c, s.Fixture.Head)

	var commits []*Commit
	NewCommitPostorderIter(commit, []plumbing.Hash{
		plumbing.NewHash("af2d6a6954d532f8ffb47615169c8fdf9d383a1a"),
	}).ForEach(func(c *Commit) error {
		commits = append(commits, c)
		return nil
	})

	c.Assert(commits, HasLen, 2)

	expected := []string{
		"6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
		"918c48b83bd081e863dbe1b80f8998f058cd8294",
	}
	for i, commit := range commits {
		c.Assert(commit.Hash.String(), Equals, expected[i])
	}
}
<commit_msg>add tests for NewCommitIterCTime and NewCommitIterBSF<commit_after>package object

import (
	"gopkg.in/src-d/go-git.v4/plumbing"

	. "gopkg.in/check.v1"
)

type CommitWalkerSuite struct {
	BaseObjectsSuite
}

var _ = Suite(&CommitWalkerSuite{})

func (s *CommitWalkerSuite) TestCommitPreIterator(c *C) {
	commit := s.commit(c, s.Fixture.Head)

	var commits []*Commit
	NewCommitPreorderIter(commit, nil, nil).ForEach(func(c *Commit) error {
		commits = append(commits, c)
		return nil
	})

	c.Assert(commits, HasLen, 8)

	expected := []string{
		"6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
		"918c48b83bd081e863dbe1b80f8998f058cd8294",
		"af2d6a6954d532f8ffb47615169c8fdf9d383a1a",
		"1669dce138d9b841a518c64b10914d88f5e488ea",
		"35e85108805c84807bc66a02d91535e1e24b38b9",
		"b029517f6300c2da0f4b651b8642506cd6aaf45d",
		"a5b8b09e2f8fcb0bb99d3ccb0958157b40890d69",
		"b8e471f58bcbca63b07bda20e428190409c2db47",
	}
	for i, commit := range commits {
		c.Assert(commit.Hash.String(), Equals, expected[i])
	}
}

func (s *CommitWalkerSuite) TestCommitPreIteratorWithIgnore(c *C) {
	commit := s.commit(c, s.Fixture.Head)

	var commits []*Commit
	NewCommitPreorderIter(commit, nil, []plumbing.Hash{
		plumbing.NewHash("af2d6a6954d532f8ffb47615169c8fdf9d383a1a"),
	}).ForEach(func(c *Commit) error {
		commits = append(commits, c)
		return nil
	})

	c.Assert(commits, HasLen, 2)

	expected := []string{
		"6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
		"918c48b83bd081e863dbe1b80f8998f058cd8294",
	}
	for i, commit := range commits {
		c.Assert(commit.Hash.String(), Equals, expected[i])
	}
}

func (s *CommitWalkerSuite) TestCommitPreIteratorWithSeenExternal(c *C) {
	commit := s.commit(c, s.Fixture.Head)

	var commits []*Commit
	seenExternal := map[plumbing.Hash]bool{
		plumbing.NewHash("af2d6a6954d532f8ffb47615169c8fdf9d383a1a"): true,
	}
	NewCommitPreorderIter(commit, seenExternal, nil).
		ForEach(func(c *Commit) error {
			commits = append(commits, c)
			return nil
		})

	c.Assert(commits, HasLen, 2)

	expected := []string{
		"6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
		"918c48b83bd081e863dbe1b80f8998f058cd8294",
	}
	for i, commit := range commits {
		c.Assert(commit.Hash.String(), Equals, expected[i])
	}
}

func (s *CommitWalkerSuite) TestCommitPostIterator(c *C) {
	commit := s.commit(c, s.Fixture.Head)

	var commits []*Commit
	NewCommitPostorderIter(commit, nil).ForEach(func(c *Commit) error {
		commits = append(commits, c)
		return nil
	})

	c.Assert(commits, HasLen, 8)

	expected := []string{
		"6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
		"918c48b83bd081e863dbe1b80f8998f058cd8294",
		"af2d6a6954d532f8ffb47615169c8fdf9d383a1a",
		"1669dce138d9b841a518c64b10914d88f5e488ea",
		"a5b8b09e2f8fcb0bb99d3ccb0958157b40890d69",
		"b8e471f58bcbca63b07bda20e428190409c2db47",
		"b029517f6300c2da0f4b651b8642506cd6aaf45d",
		"35e85108805c84807bc66a02d91535e1e24b38b9",
	}

	for i, commit := range commits {
		c.Assert(commit.Hash.String(), Equals, expected[i])
	}
}

func (s *CommitWalkerSuite) TestCommitPostIteratorWithIgnore(c *C) {
	commit := s.commit(c, s.Fixture.Head)

	var commits []*Commit
	NewCommitPostorderIter(commit, []plumbing.Hash{
		plumbing.NewHash("af2d6a6954d532f8ffb47615169c8fdf9d383a1a"),
	}).ForEach(func(c *Commit) error {
		commits = append(commits, c)
		return nil
	})

	c.Assert(commits, HasLen, 2)

	expected := []string{
		"6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
		"918c48b83bd081e863dbe1b80f8998f058cd8294",
	}
	for i, commit := range commits {
		c.Assert(commit.Hash.String(), Equals, expected[i])
	}
}

func (s *CommitWalkerSuite) TestCommitCTimeIterator(c *C) {
	commit := s.commit(c, s.Fixture.Head)

	var commits []*Commit
	NewCommitIterCTime(commit, nil, nil).ForEach(func(c *Commit) error {
		commits = append(commits, c)
		return nil
	})

	c.Assert(commits, HasLen, 8)

	expected := []string{
		"6ecf0ef2c2dffb796033e5a02219af86ec6584e5", // 2015-04-05T23:30:47+02:00
		"918c48b83bd081e863dbe1b80f8998f058cd8294", // 2015-03-31T13:56:18+02:00
		"af2d6a6954d532f8ffb47615169c8fdf9d383a1a", // 2015-03-31T13:51:51+02:00
		"1669dce138d9b841a518c64b10914d88f5e488ea", // 2015-03-31T13:48:14+02:00
		"a5b8b09e2f8fcb0bb99d3ccb0958157b40890d69", // 2015-03-31T13:47:14+02:00
		"35e85108805c84807bc66a02d91535e1e24b38b9", // 2015-03-31T13:46:24+02:00
		"b8e471f58bcbca63b07bda20e428190409c2db47", // 2015-03-31T13:44:52+02:00
		"b029517f6300c2da0f4b651b8642506cd6aaf45d", // 2015-03-31T13:42:21+02:00
	}
	for i, commit := range commits {
		c.Assert(commit.Hash.String(), Equals, expected[i])
	}
}

func (s *CommitWalkerSuite) TestCommitCTimeIteratorWithIgnore(c *C) {
	commit := s.commit(c, s.Fixture.Head)

	var commits []*Commit
	NewCommitIterCTime(commit, nil, []plumbing.Hash{
		plumbing.NewHash("af2d6a6954d532f8ffb47615169c8fdf9d383a1a"),
	}).ForEach(func(c *Commit) error {
		commits = append(commits, c)
		return nil
	})

	c.Assert(commits, HasLen, 2)

	expected := []string{
		"6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
		"918c48b83bd081e863dbe1b80f8998f058cd8294",
	}
	for i, commit := range commits {
		c.Assert(commit.Hash.String(), Equals, expected[i])
	}
}

func (s *CommitWalkerSuite) TestCommitBSFIterator(c *C) {
	commit := s.commit(c, s.Fixture.Head)

	var commits []*Commit
	NewCommitIterBSF(commit, nil, nil).ForEach(func(c *Commit) error {
		commits = append(commits, c)
		return nil
	})

	c.Assert(commits, HasLen, 8)

	expected := []string{
		"6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
		"918c48b83bd081e863dbe1b80f8998f058cd8294",
		"af2d6a6954d532f8ffb47615169c8fdf9d383a1a",
		"1669dce138d9b841a518c64b10914d88f5e488ea",
		"35e85108805c84807bc66a02d91535e1e24b38b9",
		"a5b8b09e2f8fcb0bb99d3ccb0958157b40890d69",
		"b029517f6300c2da0f4b651b8642506cd6aaf45d",
		"b8e471f58bcbca63b07bda20e428190409c2db47",
	}
	for i, commit := range commits {
		c.Assert(commit.Hash.String(), Equals, expected[i])
	}
}

func (s *CommitWalkerSuite) TestCommitBSFIteratorWithIgnore(c *C) {
	commit := s.commit(c, s.Fixture.Head)

	var commits []*Commit
	NewCommitIterBSF(commit, nil, []plumbing.Hash{
		plumbing.NewHash("af2d6a6954d532f8ffb47615169c8fdf9d383a1a"),
	}).ForEach(func(c *Commit) error {
		commits = append(commits, c)
		return nil
	})

	c.Assert(commits, HasLen, 2)

	expected := []string{
		"6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
		"918c48b83bd081e863dbe1b80f8998f058cd8294",
	}
	for i, commit := range commits {
		c.Assert(commit.Hash.String(), Equals, expected[i])
	}
}
<|endoftext|>


<commit_before>package sensitivity

import (
	"fmt"
	"strconv"
	"strings"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/intelsdi-x/athena/pkg/executor"
	"github.com/intelsdi-x/athena/pkg/snap"
	"github.com/intelsdi-x/athena/pkg/utils/err_collection"
	"github.com/intelsdi-x/swan/pkg/experiment/phase"
	"github.com/pkg/errors"
)

// measurementPhase performs a measurement for given loadPointIndex.
// User of this Phase is responsible to orchestrate this phase for each loadPoint to
// fulfill the LoadPointsCount.
type measurementPhase struct {
	namePrefix string
	// Latency Sensitivity (Production) workload.
	pr LauncherSessionPair
	// Workload Generator for Latency Sensitivity task.
	lgForPr LoadGeneratorSessionPair
	// Aggressors (Best Effort) tasks to stress LC task.
	// It can be empty in case of baseline phase.
	bes []LauncherSessionPair
	// Measurement duration in [s].
	loadDuration time.Duration
	// Number of load points to test.
	loadPointsCount int
	// Number of repetitions
	repetitions int
	// Current measurement's load point.
	currentLoadPointIndex int

	// Shared reference for measurement targetQPS resulted from Tuning Phase.
	PeakLoad *int

	activeSnapSessions       []snap.SessionHandle
	activeLaunchersTasks     []executor.TaskHandle
	activeLoadGeneratorTasks []executor.TaskHandle
}

// Returns measurement name.
func (m *measurementPhase) Name() string {
	return m.namePrefix + "_measurement_for_loadpoint_id_" +
		strconv.Itoa(m.currentLoadPointIndex)
}

// Returns number of repetitions.
func (m *measurementPhase) Repetitions() int {
	return m.repetitions
}

// Gets current loadPoint from linear function y = a * x where `x` is loadPointIndex.
func (m *measurementPhase) getLoadPoint() int {
	// Since we know that the function is satisfied
	// when TargetLoadPoint = a * loadPointsCount, we can calculate `a` parameter.
	a := float64(*m.PeakLoad) / float64(m.loadPointsCount)
	x := float64(m.currentLoadPointIndex)

	return int(a * x)
}

func (m *measurementPhase) clean() (err error) {
	var errCollection errcollection.ErrorCollection

	// Cleaning and stopping active Launchers' tasks.
	for _, task := range m.activeLaunchersTasks {
		err = task.Stop()
		if err != nil {
			errCollection.Add(errors.Wrap(err, "error while stopping task"))

			// Don't clean when stop failed.
			continue
		}

		err = task.Clean()
		if err != nil {
			errCollection.Add(errors.Wrap(err, "error while cleaning task"))
		}
	}
	m.activeLaunchersTasks = []executor.TaskHandle{}

	// Cleaning only active LoadGenerators' tasks.
	for _, task := range m.activeLoadGeneratorTasks {
		err = task.Clean()
		if err != nil {
			errCollection.Add(errors.Wrap(err, "error while cleaning task"))
		}
	}
	m.activeLoadGeneratorTasks = []executor.TaskHandle{}

	// Stopping only active Snap sessions.
	for _, snapSession := range m.activeSnapSessions {
		log.Debug("Waiting for snap session to complete it's work. ", snapSession)
		err = snapSession.Wait()
		if err != nil {
			errCollection.Add(errors.Wrap(err, "error while waiting for Snap session to complete it's work"))
		}

		err = snapSession.Stop()
		if err != nil {
			errCollection.Add(errors.Wrap(err, "error while  stopping Snap session"))
		}
	}
	m.activeSnapSessions = []snap.SessionHandle{}

	return errCollection.GetErrIfAny()
}

// Run runs a measurement for given loadPointIndex.
func (m *measurementPhase) Run(session phase.Session) error {
	if m.PeakLoad == nil {
		return errors.New("target QPS for measurement was not given")
	}

	session.LoadPointQPS = m.getLoadPoint()
	if len(m.bes) > 0 {
		session.AggressorName = ""
		for i, be := range m.bes {
			if i > 0 {
				session.AggressorName += "And"
			}

			session.AggressorName += be.Launcher.Name()
		}
	} else {
		session.AggressorName = "None"
	}

	errMsg := ""
	err := m.run(session)
	if err != nil {
		errMsg += " error while running measurement: " + err.Error()
	}

	// Make sure that deferred stops and cleans are executed.
	err = m.clean()
	if err != nil {
		errMsg += " " + err.Error()
	}

	if strings.Compare(errMsg, "") != 0 {
		log.Errorf(errMsg)
		return errors.New(errMsg)
	}

	return nil
}

func (m *measurementPhase) launchSnapSession(taskInfo executor.TaskInfo,
	session phase.Session, launcher snap.SessionLauncher) error {
	// Check if Snap Session is specified.
	if launcher != nil {
		// Launch specified Snap Session.
		tags := CreateTagConfigItem(session)
		sessionHandle, err := launcher.LaunchSession(taskInfo, tags)
		if err != nil {
			return err
		}

		// Defer stopping launched Snap Session.
		m.activeSnapSessions = append(m.activeSnapSessions, sessionHandle)
	}

	return nil
}

// run in order:
// - start HP workload
// - populate HP (with data)
// - start aggressors workloads and their snap sessions (if any)
// - start HP snap session
// - start and wait to finish for "load generator"
// - start "load generator" snap session
func (m *measurementPhase) run(session phase.Session) error {
	// TODO(bp): Here trigger Snap session for gathering platform metrics.

	// Launch Latency Sensitive workload.
	prTask, err := m.pr.Launcher.Launch()
	if err != nil {
		return err
	}
	// Defer stopping and closing the prTask.
	m.activeLaunchersTasks = append(m.activeLaunchersTasks, prTask)

	log.Debug("Populating initial test data to LC task")
	err = m.lgForPr.LoadGenerator.Populate()
	if err != nil {
		return err
	}

	// Launch specified aggressors if any.
	for _, be := range m.bes {
		beTask, err := be.Launcher.Launch()
		if err != nil {
			return err
		}
		// Defer stopping and closing the beTask.
		m.activeLaunchersTasks = append(m.activeLaunchersTasks, beTask)

		// Launch Snap Session for be workload if specified.
		err = m.launchSnapSession(beTask, session, be.SnapSessionLauncher)
		if err != nil {
			return err
		}
	}

	// TODO(bp): Push that to DB via Snap in tag or using SwanCollector.
	loadPoint := m.getLoadPoint()

	// Launch Snap Session for Latency Sensitive workload if specified.
	err = m.launchSnapSession(prTask, session, m.pr.SnapSessionLauncher)
	if err != nil {
		return err
	}

	log.Debug("Launching Load Generator with load ", loadPoint)
	loadGeneratorTask, err := m.lgForPr.LoadGenerator.Load(loadPoint, m.loadDuration)
	if err != nil {
		return err
	}

	// Defer cleaning the loadGeneratorTask.
	m.activeLoadGeneratorTasks = append(m.activeLoadGeneratorTasks, loadGeneratorTask)

	// Wait for load generation to end.
	loadGeneratorTask.Wait(0)

	// Launch Snap Session for loadGenerator if specified.
	// NOTE: Common loadGenerators don't have HTTP and just save output to the file after
	// completing the load generation.
	// To have our snap task not disabled by Snap daemon because we could not read the file during
	// load, we need to run snap session (task) only after load generation work ended.
	err = m.launchSnapSession(loadGeneratorTask, session, m.lgForPr.SnapSessionLauncher)
	if err != nil {
		return err
	}

	// Check status of load generation.
	exitCode, err := loadGeneratorTask.ExitCode()
	if err != nil {
		return err
	}

	if exitCode != 0 {
		// Load generator failed.
		return errors.Errorf("executing Load Generator returned with exit code %d", exitCode)
	}

	return nil
}

// Finalize is executed after all repetitions of given measurement.
func (m *measurementPhase) Finalize() error {
	// All data should be aggregated in Snap. So nothing to do here.
	return nil
}

// CreateTagConfigItem creates Snap-friendly tags list from session.
func CreateTagConfigItem(phaseSession phase.Session) string {
	// Constructing Tags config item as stated in
	// https://github.com/intelsdi-x/snap-plugin-processor-tag/README.md
	return fmt.Sprintf("%s:%s,%s:%s,%s:%d,%s:%d,%s:%s",
		phase.ExperimentKey, phaseSession.ExperimentID,
		phase.PhaseKey, phaseSession.PhaseID,
		phase.RepetitionKey, phaseSession.RepetitionID,
		phase.LoadPointQPSKey, phaseSession.LoadPointQPS,
		phase.AggressorNameKey, phaseSession.AggressorName,
	)
}
<commit_msg>Give enough time before killing snap sessions (#418)<commit_after>package sensitivity

import (
	"fmt"
	"strconv"
	"strings"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/intelsdi-x/athena/pkg/executor"
	"github.com/intelsdi-x/athena/pkg/snap"
	"github.com/intelsdi-x/athena/pkg/utils/err_collection"
	"github.com/intelsdi-x/swan/pkg/experiment/phase"
	"github.com/pkg/errors"
)

// measurementPhase performs a measurement for given loadPointIndex.
// User of this Phase is responsible to orchestrate this phase for each loadPoint to
// fulfill the LoadPointsCount.
type measurementPhase struct {
	namePrefix string
	// Latency Sensitivity (Production) workload.
	pr LauncherSessionPair
	// Workload Generator for Latency Sensitivity task.
	lgForPr LoadGeneratorSessionPair
	// Aggressors (Best Effort) tasks to stress LC task.
	// It can be empty in case of baseline phase.
	bes []LauncherSessionPair
	// Measurement duration in [s].
	loadDuration time.Duration
	// Number of load points to test.
	loadPointsCount int
	// Number of repetitions
	repetitions int
	// Current measurement's load point.
	currentLoadPointIndex int

	// Shared reference for measurement targetQPS resulted from Tuning Phase.
	PeakLoad *int

	activeSnapSessions       []snap.SessionHandle
	activeLaunchersTasks     []executor.TaskHandle
	activeLoadGeneratorTasks []executor.TaskHandle
}

// Returns measurement name.
func (m *measurementPhase) Name() string {
	return m.namePrefix + "_measurement_for_loadpoint_id_" +
		strconv.Itoa(m.currentLoadPointIndex)
}

// Returns number of repetitions.
func (m *measurementPhase) Repetitions() int {
	return m.repetitions
}

// Gets current loadPoint from linear function y = a * x where `x` is loadPointIndex.
func (m *measurementPhase) getLoadPoint() int {
	// Since we know that the function is satisfied
	// when TargetLoadPoint = a * loadPointsCount, we can calculate `a` parameter.
	a := float64(*m.PeakLoad) / float64(m.loadPointsCount)
	x := float64(m.currentLoadPointIndex)

	return int(a * x)
}

func (m *measurementPhase) clean() (err error) {
	var errCollection errcollection.ErrorCollection

	// Cleaning and stopping active Launchers' tasks.
	for _, task := range m.activeLaunchersTasks {
		err = task.Stop()
		if err != nil {
			errCollection.Add(errors.Wrap(err, "error while stopping task"))

			// Don't clean when stop failed.
			continue
		}

		err = task.Clean()
		if err != nil {
			errCollection.Add(errors.Wrap(err, "error while cleaning task"))
		}
	}
	m.activeLaunchersTasks = []executor.TaskHandle{}

	// Cleaning only active LoadGenerators' tasks.
	for _, task := range m.activeLoadGeneratorTasks {
		err = task.Clean()
		if err != nil {
			errCollection.Add(errors.Wrap(err, "error while cleaning task"))
		}
	}
	m.activeLoadGeneratorTasks = []executor.TaskHandle{}

	// Give enough time for executors to cleanup, before stopping the session.
	// It is workaround for metrics from publisher of loadgenerator session not always available in the storage.
	// See the description of SCE-876.
	time.Sleep(10 * time.Second)

	// Stopping only active Snap sessions.
	for _, snapSession := range m.activeSnapSessions {
		log.Debug("Waiting for snap session to complete it's work. ", snapSession)
		err = snapSession.Wait()
		if err != nil {
			errCollection.Add(errors.Wrap(err, "error while waiting for Snap session to complete it's work"))
		}

		err = snapSession.Stop()
		if err != nil {
			errCollection.Add(errors.Wrap(err, "error while  stopping Snap session"))
		}
	}
	m.activeSnapSessions = []snap.SessionHandle{}

	return errCollection.GetErrIfAny()
}

// Run runs a measurement for given loadPointIndex.
func (m *measurementPhase) Run(session phase.Session) error {
	if m.PeakLoad == nil {
		return errors.New("target QPS for measurement was not given")
	}

	session.LoadPointQPS = m.getLoadPoint()
	if len(m.bes) > 0 {
		session.AggressorName = ""
		for i, be := range m.bes {
			if i > 0 {
				session.AggressorName += "And"
			}

			session.AggressorName += be.Launcher.Name()
		}
	} else {
		session.AggressorName = "None"
	}

	errMsg := ""
	err := m.run(session)
	if err != nil {
		errMsg += " error while running measurement: " + err.Error()
	}

	// Make sure that deferred stops and cleans are executed.
	err = m.clean()
	if err != nil {
		errMsg += " " + err.Error()
	}

	if strings.Compare(errMsg, "") != 0 {
		log.Errorf(errMsg)
		return errors.New(errMsg)
	}

	return nil
}

func (m *measurementPhase) launchSnapSession(taskInfo executor.TaskInfo,
	session phase.Session, launcher snap.SessionLauncher) error {
	// Check if Snap Session is specified.
	if launcher != nil {
		// Launch specified Snap Session.
		tags := CreateTagConfigItem(session)
		sessionHandle, err := launcher.LaunchSession(taskInfo, tags)
		if err != nil {
			return err
		}

		// Defer stopping launched Snap Session.
		m.activeSnapSessions = append(m.activeSnapSessions, sessionHandle)
	}

	return nil
}

// run in order:
// - start HP workload
// - populate HP (with data)
// - start aggressors workloads and their snap sessions (if any)
// - start HP snap session
// - start and wait to finish for "load generator"
// - start "load generator" snap session
func (m *measurementPhase) run(session phase.Session) error {
	// TODO(bp): Here trigger Snap session for gathering platform metrics.

	// Launch Latency Sensitive workload.
	prTask, err := m.pr.Launcher.Launch()
	if err != nil {
		return err
	}
	// Defer stopping and closing the prTask.
	m.activeLaunchersTasks = append(m.activeLaunchersTasks, prTask)

	log.Debug("Populating initial test data to LC task")
	err = m.lgForPr.LoadGenerator.Populate()
	if err != nil {
		return err
	}

	// Launch specified aggressors if any.
	for _, be := range m.bes {
		beTask, err := be.Launcher.Launch()
		if err != nil {
			return err
		}
		// Defer stopping and closing the beTask.
		m.activeLaunchersTasks = append(m.activeLaunchersTasks, beTask)

		// Launch Snap Session for be workload if specified.
		err = m.launchSnapSession(beTask, session, be.SnapSessionLauncher)
		if err != nil {
			return err
		}
	}

	// TODO(bp): Push that to DB via Snap in tag or using SwanCollector.
	loadPoint := m.getLoadPoint()

	// Launch Snap Session for Latency Sensitive workload if specified.
	err = m.launchSnapSession(prTask, session, m.pr.SnapSessionLauncher)
	if err != nil {
		return err
	}

	log.Debug("Launching Load Generator with load ", loadPoint)
	loadGeneratorTask, err := m.lgForPr.LoadGenerator.Load(loadPoint, m.loadDuration)
	if err != nil {
		return err
	}

	// Defer cleaning the loadGeneratorTask.
	m.activeLoadGeneratorTasks = append(m.activeLoadGeneratorTasks, loadGeneratorTask)

	// Wait for load generation to end.
	loadGeneratorTask.Wait(0)

	// Launch Snap Session for loadGenerator if specified.
	// NOTE: Common loadGenerators don't have HTTP and just save output to the file after
	// completing the load generation.
	// To have our snap task not disabled by Snap daemon because we could not read the file during
	// load, we need to run snap session (task) only after load generation work ended.
	err = m.launchSnapSession(loadGeneratorTask, session, m.lgForPr.SnapSessionLauncher)
	if err != nil {
		return err
	}

	// Check status of load generation.
	exitCode, err := loadGeneratorTask.ExitCode()
	if err != nil {
		return err
	}

	if exitCode != 0 {
		// Load generator failed.
		return errors.Errorf("executing Load Generator returned with exit code %d", exitCode)
	}

	return nil
}

// Finalize is executed after all repetitions of given measurement.
func (m *measurementPhase) Finalize() error {
	// All data should be aggregated in Snap. So nothing to do here.
	return nil
}

// CreateTagConfigItem creates Snap-friendly tags list from session.
func CreateTagConfigItem(phaseSession phase.Session) string {
	// Constructing Tags config item as stated in
	// https://github.com/intelsdi-x/snap-plugin-processor-tag/README.md
	return fmt.Sprintf("%s:%s,%s:%s,%s:%d,%s:%d,%s:%s",
		phase.ExperimentKey, phaseSession.ExperimentID,
		phase.PhaseKey, phaseSession.PhaseID,
		phase.RepetitionKey, phaseSession.RepetitionID,
		phase.LoadPointQPSKey, phaseSession.LoadPointQPS,
		phase.AggressorNameKey, phaseSession.AggressorName,
	)
}
<|endoftext|>


<commit_before>package stores

import (
	"sync"

	"time"

	"github.com/davelondon/kerr"
	"golang.org/x/net/context"
	"kego.io/editor/client/actions"
	"kego.io/editor/client/models"
	"kego.io/flux"
	"kego.io/process/validate"
	"kego.io/system"
	"kego.io/system/node"
)

type RuleStore struct {
	*flux.Store
	ctx context.Context
	app *App

	m     *sync.RWMutex
	rules map[*node.Node]map[*node.Node][]system.RuleInterface
}

type ruleNotif string

func (b ruleNotif) IsNotif() {}

//const (
//RuleChanged ruleNotif = "RuleChanged"
//)

func NewRuleStore(ctx context.Context) *RuleStore {
	s := &RuleStore{
		Store: &flux.Store{},
		ctx:   ctx,
		app:   FromContext(ctx),
		m:     &sync.RWMutex{},
		rules: map[*node.Node]map[*node.Node][]system.RuleInterface{},
	}
	s.Init(s)
	return s
}

func (s *RuleStore) Get(r *node.Node, n *node.Node) []system.RuleInterface {
	s.m.RLock()
	defer s.m.RUnlock()
	root, ok := s.rules[r]
	if !ok {
		return nil
	}
	rules, ok := root[n]
	if !ok {
		return nil
	}
	return rules
}

func (s *RuleStore) Handle(payload *flux.Payload) bool {
	switch action := payload.Action.(type) {
	case *actions.InitialState:
		payload.Wait(s.app.Package, s.app.Types)
		s.validateNodes(payload, s.build(s.app.Package.Node()))
		for _, t := range s.app.Types.All() {
			s.validateNodes(payload, s.build(t))
		}
	case *actions.LoadSourceSuccess:
		payload.Wait(s.app.Branches)
		ni, ok := action.Branch.Contents.(models.NodeContentsInterface)
		if !ok {
			break
		}
		n := ni.GetNode()
		s.validateNodes(payload, s.build(n))
	case *actions.Modify:
		payload.Wait(s.app.Nodes)
		// Undo and Redo actions are always immediate.
		// New actions are immediate only if action.Immediate == true
		if action.Direction() == actions.New && !action.Immediate {
			go func() {
				<-time.After(time.Millisecond * 450)
				if action.Changed() {
					return
				}
				s.validateNodes(payload, s.build(action.Editor.Node.Root()))
			}()
		} else {
			s.validateNodes(payload, s.build(action.Editor.Node.Root()))
		}
	case *actions.Reorder:
		payload.Wait(s.app.Nodes)
		s.validateNodes(payload, s.build(action.Model.Node.Root()))
	case *actions.Delete:
		payload.Wait(s.app.Nodes)
		s.validateNodes(payload, s.build(action.Node.Root()))
	case *actions.Add:
		payload.Wait(s.app.Nodes)
		s.validateNodes(payload, s.build(action.Node.Root()))
	}
	return true
}

func (s *RuleStore) validateNodes(payload *flux.Payload, changes []*node.Node) {
	for _, n := range changes {
		m := s.app.Nodes.Get(n)
		changed, err := m.Validate(s.ctx, s.app.Rule.Get(n.Root(), n))
		if err != nil {
			s.app.Fail <- kerr.Wrap("BYQOBLPRDP", err)
			break
		}
		if changed {
			payload.Notify(n, NodeErrorsChanged)
		}
	}
}

func (s *RuleStore) build(n *node.Node) (changes []*node.Node) {
	rules := map[*node.Node][]system.RuleInterface{}
	if err := validate.BuildRulesNode(s.ctx, n, rules); err != nil {
		s.app.Fail <- kerr.Wrap("BRRRGDBXMR", err)
	}
	changes = compare(rules, s.rules[n])
	s.rules[n] = rules
	return changes
}

func compare(a, b map[*node.Node][]system.RuleInterface) (changes []*node.Node) {

	in := func(n system.RuleInterface, h []system.RuleInterface) bool {
		for _, v := range h {
			if n == v {
				return true
			}
		}
		return false
	}

	eq := func(a, b []system.RuleInterface) bool {

		if a == nil && b == nil {
			return true
		}

		if a == nil || b == nil {
			return false
		}

		if len(a) != len(b) {
			return false
		}

		for _, v := range a {
			if !in(v, b) {
				return false
			}
		}

		return true
	}

	for k, av := range a {
		if bv, ok := b[k]; !ok {
			changes = append(changes, k)
		} else {
			if !eq(av, bv) {
				changes = append(changes, k)
			}
		}
	}

	for k := range b {
		if _, ok := a[k]; !ok {
			changes = append(changes, k)
		}
	}

	return changes
}
<commit_msg>RuleStore tweaks<commit_after>package stores

import (
	"sync"

	"time"

	"github.com/davelondon/kerr"
	"golang.org/x/net/context"
	"kego.io/editor/client/actions"
	"kego.io/editor/client/models"
	"kego.io/flux"
	"kego.io/process/validate"
	"kego.io/system"
	"kego.io/system/node"
)

type RuleStore struct {
	*flux.Store
	ctx context.Context
	app *App

	m     *sync.RWMutex
	rules map[*node.Node]map[*node.Node][]system.RuleInterface
}

type ruleNotif string

func (b ruleNotif) IsNotif() {}

//const (
//RuleChanged ruleNotif = "RuleChanged"
//)

func NewRuleStore(ctx context.Context) *RuleStore {
	s := &RuleStore{
		Store: &flux.Store{},
		ctx:   ctx,
		app:   FromContext(ctx),
		m:     &sync.RWMutex{},
		rules: map[*node.Node]map[*node.Node][]system.RuleInterface{},
	}
	s.Init(s)
	return s
}

func (s *RuleStore) Get(r *node.Node, n *node.Node) []system.RuleInterface {
	s.m.RLock()
	defer s.m.RUnlock()
	root, ok := s.rules[r]
	if !ok {
		return nil
	}
	rules, ok := root[n]
	if !ok {
		return nil
	}
	return rules
}

func (s *RuleStore) Handle(payload *flux.Payload) bool {
	switch action := payload.Action.(type) {
	case *actions.InitialState:
		payload.Wait(s.app.Package, s.app.Types)
		s.validateNodes(payload, s.build(s.app.Package.Node()))
		for _, t := range s.app.Types.All() {
			s.validateNodes(payload, s.build(t))
		}
	case *actions.LoadSourceSuccess:
		payload.Wait(s.app.Branches)
		ni, ok := action.Branch.Contents.(models.NodeContentsInterface)
		if !ok {
			break
		}
		n := ni.GetNode()
		s.validateNodes(payload, s.build(n))
	case *actions.Modify:
		payload.Wait(s.app.Nodes)
		// Node mutations that are in response to keyboard input should wait an
		// additional time before doing a full validation rebuild. This
		// operation may be expensive, so we shouldn't risk interupting the
		// user input.
		if action.Direction() != actions.New || action.Immediate {
			// Undo and Redo actions are from mouse input, so always immediate.
			// New actions are immediate if action.Immediate == true
			s.validateNodes(payload, s.build(action.Editor.Node.Root()))
			break
		}
		// Delayed actions wait an extra 450ms before the validation rebuild.
		go func() {
			<-time.After(time.Millisecond * 450)
			if action.Changed() {
				return
			}
			s.validateNodes(payload, s.build(action.Editor.Node.Root()))
		}()
	case *actions.Reorder:
		payload.Wait(s.app.Nodes)
		s.validateNodes(payload, s.build(action.Model.Node.Root()))
	case *actions.Delete:
		payload.Wait(s.app.Nodes)
		s.validateNodes(payload, s.build(action.Node.Root()))
	case *actions.Add:
		payload.Wait(s.app.Nodes)
		s.validateNodes(payload, s.build(action.Node.Root()))
	}
	return true
}

func (s *RuleStore) validateNodes(payload *flux.Payload, changes []*node.Node) {
	for _, n := range changes {
		m := s.app.Nodes.Get(n)
		changed, err := m.Validate(s.ctx, s.app.Rule.Get(n.Root(), n))
		if err != nil {
			s.app.Fail <- kerr.Wrap("BYQOBLPRDP", err)
			break
		}
		if changed {
			payload.Notify(n, NodeErrorsChanged)
		}
	}
}

func (s *RuleStore) build(n *node.Node) (changes []*node.Node) {
	rules := map[*node.Node][]system.RuleInterface{}
	if err := validate.BuildRulesNode(s.ctx, n, rules); err != nil {
		s.app.Fail <- kerr.Wrap("BRRRGDBXMR", err)
	}
	changes = s.compare(rules, s.rules[n])
	s.rules[n] = rules
	return changes
}

func (s *RuleStore) compare(a, b map[*node.Node][]system.RuleInterface) (changes []*node.Node) {

	in := func(n system.RuleInterface, h []system.RuleInterface) bool {
		for _, v := range h {
			if n == v {
				return true
			}
		}
		return false
	}

	eq := func(a, b []system.RuleInterface) bool {

		if a == nil && b == nil {
			return true
		}

		if a == nil || b == nil {
			return false
		}

		if len(a) != len(b) {
			return false
		}

		for _, v := range a {
			if !in(v, b) {
				return false
			}
		}

		return true
	}

	for k, av := range a {
		if bv, ok := b[k]; !ok {
			changes = append(changes, k)
		} else {
			if !eq(av, bv) {
				changes = append(changes, k)
			}
		}
	}

	for k := range b {
		if _, ok := a[k]; !ok {
			changes = append(changes, k)
		}
	}

	return changes
}
<|endoftext|>


<commit_before>// Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"). You may
// not use this file except in compliance with the License. A copy of the
// License is located at
//
//	http://aws.amazon.com/apache2.0/
//
// or in the "license" file accompanying this file. This file 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 api

import (
	"encoding/base64"
	"fmt"
	"regexp"
	"strings"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/ecr"
	"github.com/aws/aws-sdk-go/service/ecr/ecriface"
	"github.com/awslabs/amazon-ecr-credential-helper/ecr-login/cache"
	log "github.com/cihub/seelog"
)

const proxyEndpointScheme = "https://"
const programName = "docker-credential-ecr-login"

var ecrPattern = regexp.MustCompile(`(^[a-zA-Z0-9][a-zA-Z0-9-_]*)\.dkr\.ecr\.([a-zA-Z0-9][a-zA-Z0-9-_]*)\.amazonaws\.com(\.cn)?`)

type Registry struct {
	ID	string
	Region	string
}

func ExtractRegistry(serverURL string) (*Registry, error) {
	if (strings.HasPrefix(serverURL, proxyEndpointScheme)) {
		serverURL = strings.TrimPrefix(serverURL, proxyEndpointScheme)
	}
	matches := ecrPattern.FindStringSubmatch(serverURL)
	if len(matches) == 0 {
		return nil, fmt.Errorf(programName + " can only be used with Amazon Elastic Container Registry.")
	} else if len(matches) < 3 {
		return nil, fmt.Errorf(serverURL + "is not a valid repository URI for Amazon Elastic Container Registry.")
	}
	registry := &Registry{
		ID:	matches[1],
	        Region:	matches[2],
	}
	return registry, nil
}

type Client interface {
	GetCredentials(serverURL string) (*Auth, error)
	GetCredentialsByRegistryID(registryID string) (*Auth, error)
	ListCredentials() ([]*Auth, error)
}
type defaultClient struct {
	ecrClient       ecriface.ECRAPI
	credentialCache cache.CredentialsCache
}

type Auth struct {
	ProxyEndpoint string
	Username      string
	Password      string
}

// GetCredentials returns username, password, and proxyEndpoint
func (self *defaultClient) GetCredentials(serverURL string) (*Auth, error) {
	registry, err := ExtractRegistry(serverURL)
	if err != nil {
		return nil, err
	}
	log.Debugf("Retrieving credentials for %s in %s (%s)", registry.ID, registry.Region, serverURL)
	return self.GetCredentialsByRegistryID(registry.ID)
}

// GetCredentials returns username, password, and proxyEndpoint
func (self *defaultClient) GetCredentialsByRegistryID(registryID string) (*Auth, error) {
	cachedEntry := self.credentialCache.Get(registryID)
	if cachedEntry != nil {
		if cachedEntry.IsValid(time.Now()) {
			log.Debugf("Using cached token for %s", registryID)
			return extractToken(cachedEntry.AuthorizationToken, cachedEntry.ProxyEndpoint)
		}
		log.Debugf("Cached token is no longer valid. RequestAt: %s, ExpiresAt: %s", cachedEntry.RequestedAt, cachedEntry.ExpiresAt)
	}

	auth, err := self.getAuthorizationToken(registryID)

	// if we have a cached token, fall back to avoid failing the request. This may result an expired token
	// being returned, but if there is a 500 or timeout from the service side, we'd like to attempt to re-use an
	// old token. We invalidate tokens prior to their expiration date to help mitigate this scenario.
	if err != nil && cachedEntry != nil {
		log.Infof("Got error fetching authorization token. Falling back to cached token. Error was: %s", err)
		return extractToken(cachedEntry.AuthorizationToken, cachedEntry.ProxyEndpoint)
	}
	return auth, err
}

func (self *defaultClient) ListCredentials() ([]*Auth, error) {
	auths := []*Auth{}
	for _, authEntry := range self.credentialCache.List() {
		auth, err := extractToken(authEntry.AuthorizationToken, authEntry.ProxyEndpoint)
		if err != nil {
			log.Debugf("Could not extract token: %v", err)
		} else {
			auths = append(auths, auth)
		}
	}

	// If cache is empty, get authorization token of default registry
	if len(auths) == 0 {
		log.Debug("No credential cache")
		auth, err := self.getAuthorizationToken("")
		if err != nil {
			log.Debugf("Couldn't get authorization token: %v", err)
		} else {
			auths = append(auths, auth)
		}
		return auths, err
	}

	return auths, nil
}

func (self *defaultClient) getAuthorizationToken(registryID string) (*Auth, error) {
	var input *ecr.GetAuthorizationTokenInput
        if registryID == "" {
		log.Debugf("Calling ECR.GetAuthorizationToken for default registry")
		input = &ecr.GetAuthorizationTokenInput{}
	} else {
		log.Debugf("Calling ECR.GetAuthorizationToken for %s", registryID)
		input = &ecr.GetAuthorizationTokenInput{
			RegistryIds: []*string{aws.String(registryID)},
		}
	}

	output, err := self.ecrClient.GetAuthorizationToken(input)
	if err != nil || output == nil {
		if err == nil {
			if registryID == "" {
				err = fmt.Errorf("Mising AuthorizationData in ECR response for default registry")
			} else {
				err = fmt.Errorf("Missing AuthorizationData in ECR response for %s", registryID)
			}
		}
		return nil, err
	}

	for _, authData := range output.AuthorizationData {
		if authData.ProxyEndpoint != nil && authData.AuthorizationToken != nil {
			authEntry := cache.AuthEntry{
				AuthorizationToken: aws.StringValue(authData.AuthorizationToken),
				RequestedAt:        time.Now(),
				ExpiresAt:          aws.TimeValue(authData.ExpiresAt),
				ProxyEndpoint:      aws.StringValue(authData.ProxyEndpoint),
			}
			registry, err := ExtractRegistry(authEntry.ProxyEndpoint)
			if err != nil {
				return nil, fmt.Errorf("Invalid ProxyEndpoint returned by ECR: %s", authEntry.ProxyEndpoint)
			}
			auth, err := extractToken(authEntry.AuthorizationToken, authEntry.ProxyEndpoint)
			if err != nil {
				return nil, err
			}
			self.credentialCache.Set(registry.ID, &authEntry)
			return auth, nil
		}
	}
	if registryID == "" {
		return nil, fmt.Errorf("No AuthorizationToken found for default registry")
	} else {
		return nil, fmt.Errorf("No AuthorizationToken found for %s", registryID)
	}
}

func extractToken(token string, proxyEndpoint string) (*Auth, error) {
	decodedToken, err := base64.StdEncoding.DecodeString(token)
	if err != nil {
		return nil, fmt.Errorf("Invalid token: %v:", err)
	}

	parts := strings.SplitN(string(decodedToken), ":", 2)
	if len(parts) < 2 {
		return nil, fmt.Errorf("Invalid token: expected two parts, got %n", len(parts))
	}

	return &Auth{
		Username:      parts[0],
		Password:      parts[1],
		ProxyEndpoint: proxyEndpoint,
	}, nil
}
<commit_msg>api: fix bad format verb<commit_after>// Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"). You may
// not use this file except in compliance with the License. A copy of the
// License is located at
//
//	http://aws.amazon.com/apache2.0/
//
// or in the "license" file accompanying this file. This file 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 api

import (
	"encoding/base64"
	"fmt"
	"regexp"
	"strings"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/ecr"
	"github.com/aws/aws-sdk-go/service/ecr/ecriface"
	"github.com/awslabs/amazon-ecr-credential-helper/ecr-login/cache"
	log "github.com/cihub/seelog"
)

const proxyEndpointScheme = "https://"
const programName = "docker-credential-ecr-login"

var ecrPattern = regexp.MustCompile(`(^[a-zA-Z0-9][a-zA-Z0-9-_]*)\.dkr\.ecr\.([a-zA-Z0-9][a-zA-Z0-9-_]*)\.amazonaws\.com(\.cn)?`)

type Registry struct {
	ID     string
	Region string
}

func ExtractRegistry(serverURL string) (*Registry, error) {
	if strings.HasPrefix(serverURL, proxyEndpointScheme) {
		serverURL = strings.TrimPrefix(serverURL, proxyEndpointScheme)
	}
	matches := ecrPattern.FindStringSubmatch(serverURL)
	if len(matches) == 0 {
		return nil, fmt.Errorf(programName + " can only be used with Amazon Elastic Container Registry.")
	} else if len(matches) < 3 {
		return nil, fmt.Errorf(serverURL + "is not a valid repository URI for Amazon Elastic Container Registry.")
	}
	registry := &Registry{
		ID:     matches[1],
		Region: matches[2],
	}
	return registry, nil
}

type Client interface {
	GetCredentials(serverURL string) (*Auth, error)
	GetCredentialsByRegistryID(registryID string) (*Auth, error)
	ListCredentials() ([]*Auth, error)
}
type defaultClient struct {
	ecrClient       ecriface.ECRAPI
	credentialCache cache.CredentialsCache
}

type Auth struct {
	ProxyEndpoint string
	Username      string
	Password      string
}

// GetCredentials returns username, password, and proxyEndpoint
func (self *defaultClient) GetCredentials(serverURL string) (*Auth, error) {
	registry, err := ExtractRegistry(serverURL)
	if err != nil {
		return nil, err
	}
	log.Debugf("Retrieving credentials for %s in %s (%s)", registry.ID, registry.Region, serverURL)
	return self.GetCredentialsByRegistryID(registry.ID)
}

// GetCredentials returns username, password, and proxyEndpoint
func (self *defaultClient) GetCredentialsByRegistryID(registryID string) (*Auth, error) {
	cachedEntry := self.credentialCache.Get(registryID)
	if cachedEntry != nil {
		if cachedEntry.IsValid(time.Now()) {
			log.Debugf("Using cached token for %s", registryID)
			return extractToken(cachedEntry.AuthorizationToken, cachedEntry.ProxyEndpoint)
		}
		log.Debugf("Cached token is no longer valid. RequestAt: %s, ExpiresAt: %s", cachedEntry.RequestedAt, cachedEntry.ExpiresAt)
	}

	auth, err := self.getAuthorizationToken(registryID)

	// if we have a cached token, fall back to avoid failing the request. This may result an expired token
	// being returned, but if there is a 500 or timeout from the service side, we'd like to attempt to re-use an
	// old token. We invalidate tokens prior to their expiration date to help mitigate this scenario.
	if err != nil && cachedEntry != nil {
		log.Infof("Got error fetching authorization token. Falling back to cached token. Error was: %s", err)
		return extractToken(cachedEntry.AuthorizationToken, cachedEntry.ProxyEndpoint)
	}
	return auth, err
}

func (self *defaultClient) ListCredentials() ([]*Auth, error) {
	auths := []*Auth{}
	for _, authEntry := range self.credentialCache.List() {
		auth, err := extractToken(authEntry.AuthorizationToken, authEntry.ProxyEndpoint)
		if err != nil {
			log.Debugf("Could not extract token: %v", err)
		} else {
			auths = append(auths, auth)
		}
	}

	// If cache is empty, get authorization token of default registry
	if len(auths) == 0 {
		log.Debug("No credential cache")
		auth, err := self.getAuthorizationToken("")
		if err != nil {
			log.Debugf("Couldn't get authorization token: %v", err)
		} else {
			auths = append(auths, auth)
		}
		return auths, err
	}

	return auths, nil
}

func (self *defaultClient) getAuthorizationToken(registryID string) (*Auth, error) {
	var input *ecr.GetAuthorizationTokenInput
	if registryID == "" {
		log.Debugf("Calling ECR.GetAuthorizationToken for default registry")
		input = &ecr.GetAuthorizationTokenInput{}
	} else {
		log.Debugf("Calling ECR.GetAuthorizationToken for %s", registryID)
		input = &ecr.GetAuthorizationTokenInput{
			RegistryIds: []*string{aws.String(registryID)},
		}
	}

	output, err := self.ecrClient.GetAuthorizationToken(input)
	if err != nil || output == nil {
		if err == nil {
			if registryID == "" {
				err = fmt.Errorf("Mising AuthorizationData in ECR response for default registry")
			} else {
				err = fmt.Errorf("Missing AuthorizationData in ECR response for %s", registryID)
			}
		}
		return nil, err
	}

	for _, authData := range output.AuthorizationData {
		if authData.ProxyEndpoint != nil && authData.AuthorizationToken != nil {
			authEntry := cache.AuthEntry{
				AuthorizationToken: aws.StringValue(authData.AuthorizationToken),
				RequestedAt:        time.Now(),
				ExpiresAt:          aws.TimeValue(authData.ExpiresAt),
				ProxyEndpoint:      aws.StringValue(authData.ProxyEndpoint),
			}
			registry, err := ExtractRegistry(authEntry.ProxyEndpoint)
			if err != nil {
				return nil, fmt.Errorf("Invalid ProxyEndpoint returned by ECR: %s", authEntry.ProxyEndpoint)
			}
			auth, err := extractToken(authEntry.AuthorizationToken, authEntry.ProxyEndpoint)
			if err != nil {
				return nil, err
			}
			self.credentialCache.Set(registry.ID, &authEntry)
			return auth, nil
		}
	}
	if registryID == "" {
		return nil, fmt.Errorf("No AuthorizationToken found for default registry")
	} else {
		return nil, fmt.Errorf("No AuthorizationToken found for %s", registryID)
	}
}

func extractToken(token string, proxyEndpoint string) (*Auth, error) {
	decodedToken, err := base64.StdEncoding.DecodeString(token)
	if err != nil {
		return nil, fmt.Errorf("Invalid token: %v:", err)
	}

	parts := strings.SplitN(string(decodedToken), ":", 2)
	if len(parts) < 2 {
		return nil, fmt.Errorf("Invalid token: expected two parts, got %d", len(parts))
	}

	return &Auth{
		Username:      parts[0],
		Password:      parts[1],
		ProxyEndpoint: proxyEndpoint,
	}, nil
}
<|endoftext|>


<commit_before>package middleware

import (
	"context"
	"fmt"
	"net/http"

	dd_opentracing "github.com/DataDog/dd-trace-go/opentracing"
	dd_ext "github.com/DataDog/dd-trace-go/tracer/ext"
	opentracing "github.com/opentracing/opentracing-go"
	"github.com/opentracing/opentracing-go/ext"
	"github.com/remind101/pkg/httpx"
)

type OpentracingTracer struct {
	handler httpx.Handler
	router  *httpx.Router
}

func OpentracingTracing(h httpx.Handler, router *httpx.Router) *OpentracingTracer {
	return &OpentracingTracer{h, router}
}

func (h *OpentracingTracer) ServeHTTPContext(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
	path := templatePath(h.router, r)
	route := fmt.Sprintf("%s %s", r.Method, path)

	var span opentracing.Span
	wireContext, err := opentracing.GlobalTracer().Extract(
		opentracing.HTTPHeaders,
		opentracing.HTTPHeadersCarrier(r.Header))
	if err != nil {
		span = opentracing.StartSpan("server.request")
	} else {
		span = opentracing.StartSpan("server.request", ext.RPCServerOption(wireContext))
	}
	span.SetTag(dd_opentracing.ResourceName, route)
	span.SetTag(dd_opentracing.SpanType, "web")
	span.SetTag(dd_ext.HTTPMethod, r.Method)
	span.SetTag(dd_ext.HTTPURL, r.RequestURI)

	if rid := httpx.RequestID(ctx); rid != "" {
		span.SetTag("request_id", rid)
	}

	defer span.Finish()
	ctx = opentracing.ContextWithSpan(ctx, span)

	rw := NewResponseWriter(w)
	reqErr := h.handler.ServeHTTPContext(ctx, rw, r)

	span.SetTag(dd_ext.HTTPCode, rw.Status())
	if reqErr != nil {
		span.SetTag(dd_ext.ErrorMsg, reqErr.Error())
	}

	return reqErr
}
<commit_msg>Set error<commit_after>package middleware

import (
	"context"
	"fmt"
	"net/http"

	dd_opentracing "github.com/DataDog/dd-trace-go/opentracing"
	dd_ext "github.com/DataDog/dd-trace-go/tracer/ext"
	opentracing "github.com/opentracing/opentracing-go"
	"github.com/opentracing/opentracing-go/ext"
	"github.com/remind101/pkg/httpx"
)

type OpentracingTracer struct {
	handler httpx.Handler
	router  *httpx.Router
}

func OpentracingTracing(h httpx.Handler, router *httpx.Router) *OpentracingTracer {
	return &OpentracingTracer{h, router}
}

func (h *OpentracingTracer) ServeHTTPContext(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
	path := templatePath(h.router, r)
	route := fmt.Sprintf("%s %s", r.Method, path)

	var span opentracing.Span
	wireContext, err := opentracing.GlobalTracer().Extract(
		opentracing.HTTPHeaders,
		opentracing.HTTPHeadersCarrier(r.Header))
	if err != nil {
		span = opentracing.StartSpan("server.request")
	} else {
		span = opentracing.StartSpan("server.request", ext.RPCServerOption(wireContext))
	}
	span.SetTag(dd_opentracing.ResourceName, route)
	span.SetTag(dd_opentracing.SpanType, "web")
	span.SetTag(dd_ext.HTTPMethod, r.Method)
	span.SetTag(dd_ext.HTTPURL, r.RequestURI)

	if rid := httpx.RequestID(ctx); rid != "" {
		span.SetTag("request_id", rid)
	}

	defer span.Finish()
	ctx = opentracing.ContextWithSpan(ctx, span)

	rw := NewResponseWriter(w)
	reqErr := h.handler.ServeHTTPContext(ctx, rw, r)
	if reqErr != nil {
		span.SetTag(dd_opentracing.Error, reqErr)
	}
	span.SetTag(dd_ext.HTTPCode, rw.Status())

	return reqErr
}
<|endoftext|>


<commit_before>// Copyright 2015 The Cockroach 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.
//
// Author: Peter Mattis (peter@cockroachlabs.com)

package sql_test

import (
	"bytes"
	"database/sql"
	"flag"
	"fmt"
	"math/rand"
	"testing"

	"github.com/cockroachdb/cockroach/security"
	"github.com/cockroachdb/cockroach/server"
	"github.com/cockroachdb/cockroach/util/log"
)

var maxTransfer = flag.Int("max-transfer", 999, "Maximum amount to transfer in one transaction.")
var numAccounts = flag.Int("num-accounts", 999, "Number of accounts.")

// BenchmarkBank mirrors the SQL performed by examples/sql_bank, but structured
// as a benchmark for easier usage of the Go performance analysis tools like
// pprof, memprof and trace.
func BenchmarkBank(b *testing.B) {
	s := server.StartTestServer(b)
	defer s.Stop()

	db, err := sql.Open("cockroach", "https://root@"+s.ServingAddr()+"?certs="+security.EmbeddedCertsDir)
	if err != nil {
		b.Fatal(err)
	}
	defer db.Close()

	if _, err := db.Exec(`CREATE DATABASE IF NOT EXISTS bank`); err != nil {
		b.Fatal(err)
	}

	{
		// Initialize the "accounts" table.
		schema := `
CREATE TABLE IF NOT EXISTS bank.accounts (
  id INT PRIMARY KEY,
  balance INT NOT NULL
)`
		if _, err = db.Exec(schema); err != nil {
			b.Fatal(err)
		}
		if _, err = db.Exec("TRUNCATE TABLE bank.accounts"); err != nil {
			b.Fatal(err)
		}

		var placeholders bytes.Buffer
		var values []interface{}
		for i := 0; i < *numAccounts; i++ {
			if i > 0 {
				placeholders.WriteString(", ")
			}
			fmt.Fprintf(&placeholders, "($%d, 0)", i+1)
			values = append(values, i)
		}
		stmt := `INSERT INTO bank.accounts (id, balance) VALUES ` + placeholders.String()
		if _, err = db.Exec(stmt, values...); err != nil {
			b.Fatal(err)
		}
	}

	b.ResetTimer()
	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			from := rand.Intn(*numAccounts)
			to := rand.Intn(*numAccounts - 1)
			if from == to {
				to = *numAccounts - 1
			}

			amount := rand.Intn(*maxTransfer)

			update := `
UPDATE bank.accounts
  SET balance = CASE id WHEN $1 THEN balance-$3 WHEN $2 THEN balance+$3 END
  WHERE id IN ($1, $2) AND (SELECT balance >= $3 FROM bank.accounts WHERE id = $1)
`
			if _, err = db.Exec(update, from, to, amount); err != nil {
				if log.V(1) {
					log.Warning(err)
				}
				continue
			}
		}
	})
	b.StopTimer()
}
<commit_msg>Use pgwire instead of the cockroach https driver.<commit_after>// Copyright 2015 The Cockroach 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.
//
// Author: Peter Mattis (peter@cockroachlabs.com)

package sql_test

import (
	"bytes"
	"database/sql"
	"flag"
	"fmt"
	"math/rand"
	"testing"

	"github.com/cockroachdb/cockroach/util/log"
)

var maxTransfer = flag.Int("max-transfer", 999, "Maximum amount to transfer in one transaction.")
var numAccounts = flag.Int("num-accounts", 999, "Number of accounts.")

// runBenchmarkBank mirrors the SQL performed by examples/sql_bank, but
// structured as a benchmark for easier usage of the Go performance analysis
// tools like pprof, memprof and trace.
func runBenchmarkBank(b *testing.B, db *sql.DB) {
	if _, err := db.Exec(`CREATE DATABASE IF NOT EXISTS bank`); err != nil {
		b.Fatal(err)
	}

	{
		// Initialize the "accounts" table.
		schema := `
CREATE TABLE IF NOT EXISTS bank.accounts (
  id INT PRIMARY KEY,
  balance INT NOT NULL
)`
		if _, err := db.Exec(schema); err != nil {
			b.Fatal(err)
		}
		if _, err := db.Exec("TRUNCATE TABLE bank.accounts"); err != nil {
			b.Fatal(err)
		}

		var values bytes.Buffer
		for i := 0; i < *numAccounts; i++ {
			if i > 0 {
				values.WriteString(", ")
			}
			fmt.Fprintf(&values, "(%d, 0)", i)
		}
		stmt := `INSERT INTO bank.accounts (id, balance) VALUES ` + values.String()
		if _, err := db.Exec(stmt); err != nil {
			b.Fatal(err)
		}
	}

	b.ResetTimer()
	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			from := rand.Intn(*numAccounts)
			to := rand.Intn(*numAccounts - 1)
			if from == to {
				to = *numAccounts - 1
			}

			amount := rand.Intn(*maxTransfer)

			update := `
UPDATE bank.accounts
  SET balance = CASE id WHEN $1 THEN balance-$3 WHEN $2 THEN balance+$3 END
  WHERE id IN ($1, $2) AND (SELECT balance >= $3 FROM bank.accounts WHERE id = $1)
`
			if _, err := db.Exec(update, from, to, amount); err != nil {
				if log.V(1) {
					log.Warning(err)
				}
				continue
			}
		}
	})
	b.StopTimer()
}

func BenchmarkBank(b *testing.B) {
	benchmarkCockroach(b, runBenchmarkBank)
}
<|endoftext|>


<commit_before>package ami

// AbsoluteTimeout set absolute timeout.
// Hangup a channel after a certain time. Acknowledges set time with Timeout Set message.
func AbsoluteTimeout(client Client, actionID, channel string, timeout int) (Response, error) {
	return send(client, "AbsoluteTimeout", actionID, map[string]interface{}{
		"Channel": channel,
		"Timeout": timeout,
	})
}

// Atxfer attended transfer.
func Atxfer(client Client, actionID, channel, exten, context, priority string) (Response, error) {
	return send(client, "AbsoluteTimeout", actionID, map[string]string{
		"Channel":  channel,
		"Exten":    exten,
		"Context":  context,
		"Priority": priority,
	})
}

// Bridge bridges two channels already in the PBX.
func Bridge(client Client, actionID, channel1, channel2 string, tone bool) (Response, error) {
	t := map[bool]string{false: "no", true: "yes"}
	return send(client, "Bridge", actionID, map[string]string{
		"Channel1": channel1,
		"Channel2": channel2,
		"Tone":     t[tone],
	})
}

// CoreShowChannels list currently active channels.
func CoreShowChannels(client Client, actionID string) ([]Response, error) {
	return requestList(client, "CoreShowChannels", actionID, "CoreShowChannel", "CoreShowChannelsComplete")
}

// ExtensionState checks extension status.
func ExtensionState(client Client, actionID, exten, context string) (Response, error) {
	return send(client, "ExtensionState", actionID, map[string]string{
		"Exten":   exten,
		"Context": context,
	})
}

// Hangup hangups channel.
func Hangup(client Client, actionID, channel, cause string) (Response, error) {
	return send(client, "Hangup", actionID, map[string]string{
		"Channel": channel,
		"Cause":   cause,
	})
}

// Originate originates a call.
// Generates an outgoing call to a Extension/Context/Priority or Application/Data.
func Originate(client Client, actionID string, originate OriginateData) (Response, error) {
	return send(client, "Originate", actionID, originate)
}

// Park parks a channel.
func Park(client Client, actionID, channel1, channel2 string, timeout int, parkinglot string) (Response, error) {
	return send(client, "Park", actionID, map[string]interface{}{
		"Channel":    channel1,
		"Channel2":   channel2,
		"Timeout":    timeout,
		"Parkinglot": parkinglot,
	})
}

// ParkedCalls list parked calls.
func ParkedCalls(client Client, actionID string) ([]Response, error) {
	return requestList(client, "ParkedCalls", actionID, "ParkedCall", "ParkedCallsComplete")
}

// PlayDTMF plays DTMF signal on a specific channel.
func PlayDTMF(client Client, actionID, channel, digit string) (Response, error) {
	return send(client, "PlayDTMF", actionID, map[string]string{
		"Channel": channel,
		"Digit":   digit,
	})
}

// Redirect redirects (transfer) a call.
func Redirect(client Client, actionID string, call CallData) (Response, error) {
	return send(client, "Redirect", actionID, call)
}

// SendText sends text message to channel.
func SendText(client Client, actionID, channel, msg string) (Response, error) {
	return send(client, "SendText", actionID, map[string]string{
		"Channel": channel,
		"Message": msg,
	})
}

// Setvar sets a channel variable. Sets a global or local channel variable.
// Note: If a channel name is not provided then the variable is global.
func Setvar(client Client, actionID, channel, variable, value string) (Response, error) {
	return send(client, "Setvar", actionID, map[string]string{
		"Channel":  channel,
		"Variable": variable,
		"Value":    value,
	})
}

// Status lists channel status.
// Will return the status information of each channel along with the value for the specified channel variables.
func Status(client Client, actionID, channel, variables string) (Response, error) {
	return send(client, "Status", actionID, map[string]string{
		"Channel":   channel,
		"Variables": variables,
	})
}

// AGI add an AGI command to execute by Async AGI.
func AGI(client Client, actionID, channel, agiCommand, agiCommandID string) (Response, error) {
	return send(client, "AGI", actionID, map[string]string{
		"Channel":   channel,
		"Command":   agiCommand,
		"CommandID": agiCommandID,
	})
}

// AOCMessage generates an Advice of Charge message on a channel.
func AOCMessage(client Client, actionID string, aocData AOCData) (Response, error) {
	return send(client, "AOCMessage", actionID, aocData)
}

// Getvar gets a channel variable.
func Getvar(client Client, actionID, channel, variable string) (Response, error) {
	return send(client, "Getvar", actionID, map[string]string{
		"Channel":  channel,
		"Variable": variable,
	})
}

// LocalOptimizeAway optimize away a local channel when possible.
// A local channel created with "/n" will not automatically optimize away.
// Calling this command on the local channel will clear that flag and allow it to optimize away if it's bridged or when it becomes bridged.
func LocalOptimizeAway(client Client, actionID, channel string) (Response, error) {
	return send(client, "LocalOptimizeAway", actionID, map[string]string{
		"Channel": channel,
	})
}
<commit_msg>Fix Atxfer action<commit_after>package ami

// AbsoluteTimeout set absolute timeout.
// Hangup a channel after a certain time. Acknowledges set time with Timeout Set message.
func AbsoluteTimeout(client Client, actionID, channel string, timeout int) (Response, error) {
	return send(client, "AbsoluteTimeout", actionID, map[string]interface{}{
		"Channel": channel,
		"Timeout": timeout,
	})
}

// Atxfer attended transfer.
func Atxfer(client Client, actionID, channel, exten, context, priority string) (Response, error) {
	return send(client, "Atxfer", actionID, map[string]string{
		"Channel":  channel,
		"Exten":    exten,
		"Context":  context,
		"Priority": priority,
	})
}

// Bridge bridges two channels already in the PBX.
func Bridge(client Client, actionID, channel1, channel2 string, tone bool) (Response, error) {
	t := map[bool]string{false: "no", true: "yes"}
	return send(client, "Bridge", actionID, map[string]string{
		"Channel1": channel1,
		"Channel2": channel2,
		"Tone":     t[tone],
	})
}

// CoreShowChannels list currently active channels.
func CoreShowChannels(client Client, actionID string) ([]Response, error) {
	return requestList(client, "CoreShowChannels", actionID, "CoreShowChannel", "CoreShowChannelsComplete")
}

// ExtensionState checks extension status.
func ExtensionState(client Client, actionID, exten, context string) (Response, error) {
	return send(client, "ExtensionState", actionID, map[string]string{
		"Exten":   exten,
		"Context": context,
	})
}

// Hangup hangups channel.
func Hangup(client Client, actionID, channel, cause string) (Response, error) {
	return send(client, "Hangup", actionID, map[string]string{
		"Channel": channel,
		"Cause":   cause,
	})
}

// Originate originates a call.
// Generates an outgoing call to a Extension/Context/Priority or Application/Data.
func Originate(client Client, actionID string, originate OriginateData) (Response, error) {
	return send(client, "Originate", actionID, originate)
}

// Park parks a channel.
func Park(client Client, actionID, channel1, channel2 string, timeout int, parkinglot string) (Response, error) {
	return send(client, "Park", actionID, map[string]interface{}{
		"Channel":    channel1,
		"Channel2":   channel2,
		"Timeout":    timeout,
		"Parkinglot": parkinglot,
	})
}

// ParkedCalls list parked calls.
func ParkedCalls(client Client, actionID string) ([]Response, error) {
	return requestList(client, "ParkedCalls", actionID, "ParkedCall", "ParkedCallsComplete")
}

// PlayDTMF plays DTMF signal on a specific channel.
func PlayDTMF(client Client, actionID, channel, digit string) (Response, error) {
	return send(client, "PlayDTMF", actionID, map[string]string{
		"Channel": channel,
		"Digit":   digit,
	})
}

// Redirect redirects (transfer) a call.
func Redirect(client Client, actionID string, call CallData) (Response, error) {
	return send(client, "Redirect", actionID, call)
}

// SendText sends text message to channel.
func SendText(client Client, actionID, channel, msg string) (Response, error) {
	return send(client, "SendText", actionID, map[string]string{
		"Channel": channel,
		"Message": msg,
	})
}

// Setvar sets a channel variable. Sets a global or local channel variable.
// Note: If a channel name is not provided then the variable is global.
func Setvar(client Client, actionID, channel, variable, value string) (Response, error) {
	return send(client, "Setvar", actionID, map[string]string{
		"Channel":  channel,
		"Variable": variable,
		"Value":    value,
	})
}

// Status lists channel status.
// Will return the status information of each channel along with the value for the specified channel variables.
func Status(client Client, actionID, channel, variables string) (Response, error) {
	return send(client, "Status", actionID, map[string]string{
		"Channel":   channel,
		"Variables": variables,
	})
}

// AGI add an AGI command to execute by Async AGI.
func AGI(client Client, actionID, channel, agiCommand, agiCommandID string) (Response, error) {
	return send(client, "AGI", actionID, map[string]string{
		"Channel":   channel,
		"Command":   agiCommand,
		"CommandID": agiCommandID,
	})
}

// AOCMessage generates an Advice of Charge message on a channel.
func AOCMessage(client Client, actionID string, aocData AOCData) (Response, error) {
	return send(client, "AOCMessage", actionID, aocData)
}

// Getvar gets a channel variable.
func Getvar(client Client, actionID, channel, variable string) (Response, error) {
	return send(client, "Getvar", actionID, map[string]string{
		"Channel":  channel,
		"Variable": variable,
	})
}

// LocalOptimizeAway optimize away a local channel when possible.
// A local channel created with "/n" will not automatically optimize away.
// Calling this command on the local channel will clear that flag and allow it to optimize away if it's bridged or when it becomes bridged.
func LocalOptimizeAway(client Client, actionID, channel string) (Response, error) {
	return send(client, "LocalOptimizeAway", actionID, map[string]string{
		"Channel": channel,
	})
}
<|endoftext|>