<commit_before>package main

import (
	"bufio"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
)

// Gotcha for search recursive
type Gotcha struct {
	W   io.Writer
	Log *log.Logger

	// options
	Word           string
	TypesMap       map[string]bool
	IgnoreDirsMap  map[string]bool
	IgnoreBasesMap map[string]bool
	IgnoreTypesMap map[string]bool

	// TODO: consider
	MaxRune int
	Add     uint64
	Trim    bool
	Abort   bool

	nfiles uint64
	nlines uint64
}

// NewGotcha allocation for Gotcha
func NewGotcha() *Gotcha {
	makeBoolMap := func(list []string) map[string]bool {
		m := make(map[string]bool)
		for _, s := range list {
			m[s] = true
		}
		return m
	}
	return &Gotcha{
		W:   os.Stdout,
		Log: log.New(ioutil.Discard, "[todogotcha]:", log.Lshortfile),

		Word:           "TODO: ",
		TypesMap:       make(map[string]bool),
		IgnoreDirsMap:  makeBoolMap(IgnoreDirs),
		IgnoreBasesMap: makeBoolMap(IgnoreBases),
		IgnoreTypesMap: makeBoolMap(IgnoreTypes),

		MaxRune: 512,
		Add:     0,
		Trim:    false,
		Abort:   false,

		nfiles: 0,
		nlines: 0,
	}
}

// PrintTotal prnt nfiles and ncontents
func (g *Gotcha) PrintTotal() (int, error) {
	return fmt.Fprintf(g.W, "files %d\nlines %d\n", g.nfiles, g.nlines)
}

func (g *Gotcha) isTarget(path string) bool {
	if g.IgnoreBasesMap[path] {
		return false
	}
	ext := filepath.Ext(path)
	if g.IgnoreTypesMap[ext] {
		return false
	}
	if len(g.TypesMap) == 0 {
		return true
	}
	return g.TypesMap[ext]
}

// TODO: consider name
type gatherRes struct {
	path     string
	contents []string
	err      error
}

func (gr *gatherRes) Error() string {
	if gr.err == ErrHaveTooLongLine {
		return gr.err.Error() + ":" + gr.path
	}
	return gr.err.Error()
}

// ErrHaveTooLongLine read limit of over
var ErrHaveTooLongLine = errors.New("have too long line")

// IsTooLong check ErrHaveTooLongLine
func IsTooLong(err error) bool {
	switch e := err.(type) {
	case *gatherRes:
		return e.err == ErrHaveTooLongLine
	}
	return false
}

func (g *Gotcha) gather(path string) *gatherRes {
	gr := &gatherRes{path: path}
	var f *os.File
	f, gr.err = os.Open(path)
	if gr.err != nil {
		return gr
	}
	defer f.Close()

	sc := bufio.NewScanner(f)
	index := -1
	lineCount := uint64(1) // TODO: consider to zero
	addCount := uint64(0)

	var push func()
	if g.Trim {
		push = func() {
			gr.contents = append(gr.contents, fmt.Sprintf("L%v:%s", lineCount, sc.Text()[index+len(g.Word):]))
			addCount = 1
		}
	} else {
		push = func() {
			gr.contents = append(gr.contents, fmt.Sprintf("L%v:%s", lineCount, sc.Text()))
			addCount = 1
		}
	}

	var pushNextLines func()
	if g.Add != 0 {
		pushNextLines = func() {
			if addCount != 0 && addCount <= g.Add {
				gr.contents = append(gr.contents, fmt.Sprintf(" %v:%s", lineCount, sc.Text()))
				addCount++
			} else {
				addCount = 0
			}
		}
	} else {
		// discard
		pushNextLines = func() {}
	}

	for ; sc.Scan(); lineCount++ {
		if gr.err = sc.Err(); gr.err != nil {
			return gr
		}
		if g.MaxRune > 0 && len(sc.Text()) > g.MaxRune {
			gr.err = ErrHaveTooLongLine
			return gr
		}
		if index = strings.Index(sc.Text(), g.Word); index != -1 {
			push()
			continue
		}
		pushNextLines()
	}
	return gr
}

// WorkGo run on async
func (g *Gotcha) WorkGo(root string, nworker uint64) (exitCode int) {
	// queue -> gatherQueue -> res
	var (
		wg          = new(sync.WaitGroup)
		queue       = make(chan string, 512)
		gatherQueue = make(chan string, 512)
		res         = make(chan *gatherRes, 512)
		errch       = make(chan error, 128)
	)

	// TODO: consider really need? goCounter
	var (
		goCounter = uint64(0)
		done      = make(chan bool)
	)
	defer func() {
		for ; goCounter != 0; goCounter-- {
			done <- true
		}
	}()

	// TODO: consider
	if nworker == 0 {
		nworker = func() uint64 {
			n := runtime.NumCPU() / 2
			if n < 0 {
				return 0
			}
			return uint64(n)
		}()
	}

	// error handler
	// TODO: consider error handling
	//     : this is maybe discard some errors
	goCounter++
	go func() {
		for {
			select {
			case err := <-errch:
				// TODO: error handling
				if err != nil {
					exitCode = 1 // TODO: consider exitCode
					switch {
					case g.Abort:
						g.Log.Fatal(err) // TODO: consider not use panic
					case IsTooLong(err), os.IsPermission(err), os.IsNotExist(err):
						g.Log.Println(err)
						continue
					default:
						g.Log.Fatalln("unknown error:", err)
						//panic(err) // TODO: consider not use panic
					}
				}
			case <-done:
				return
			}
		}
	}()

	// woker
	for i := uint64(0); i <= nworker; i++ {
		goCounter++
		go func() {
			for {
				select {
				case path := <-gatherQueue:
					res <- g.gather(path)
				case <-done:
					return
				}
			}
		}()
	}

	// res with write
	goCounter++
	go func() {
		for {
			select {
			case gr := <-res:
				switch {
				case gr.err != nil:
					if gr.err == ErrHaveTooLongLine {
						errch <- gr
					} else {
						errch <- gr.err
					}
				case len(gr.contents) != 0:
					_, err := fmt.Fprintf(g.W, "%s\n%s\n\n", gr.path, strings.Join(gr.contents, "\n"))
					if err != nil {
						errch <- err
					}
					g.nfiles++
					g.nlines += uint64(len(gr.contents))
				}
				wg.Done()
			case <-done:
				return
			}
		}
	}()

	// walker
	goCounter++
	go func() {
		for {
			select {
			case dir := <-queue:
				infos, err := ioutil.ReadDir(dir)
				if err != nil {
					errch <- err
					wg.Done()
					continue
				}
				for _, info := range infos {
					path := filepath.Join(dir, info.Name())
					switch {
					case info.IsDir() && !g.IgnoreDirsMap[info.Name()]:
						// TODO: consider another way
						wg.Add(1)
						go func(path string) { queue <- path }(path)
						continue
					case info.Mode().IsRegular() && g.isTarget(info.Name()):
						wg.Add(1)
						gatherQueue <- path
						continue
					}
				}
				wg.Done()
			case <-done:
				return
			}
		}
	}()

	wg.Add(1)
	queue <- root
	wg.Wait()
	return exitCode
}

// SyncWorkGo run on sync
func (g *Gotcha) SyncWorkGo(root string) error {
	return filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if info.IsDir() && g.IgnoreDirsMap[info.Name()] {
			return filepath.SkipDir
		}
		if info.Mode().IsRegular() && g.isTarget(info.Name()) {
			gr := g.gather(path)
			if gr.err != nil {
				switch {
				case g.Abort:
					g.Log.Fatal(gr.err) // TODO: consider not use panic
				case IsTooLong(gr):
					g.Log.Print(gr)
				case os.IsPermission(gr.err) || os.IsNotExist(gr.err):
					g.Log.Print(gr.err)
				default:
					g.Log.Print(gr.err) // TODO: consider not use panic
				}
				return nil
			}
			if len(gr.contents) != 0 {
				_, err = fmt.Fprintf(g.W, "%s\n%s\n\n", gr.path, strings.Join(gr.contents, "\n"))
				g.nfiles++
				g.nlines += uint64(len(gr.contents))
			}
		}
		return err
	})
}
<commit_msg>fix comment  Changes to be committed: 	modified:   todogotcha/gotcha.go<commit_after>package main

import (
	"bufio"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
)

// Gotcha for search recursive
type Gotcha struct {
	W   io.Writer
	Log *log.Logger

	// options
	Word           string
	TypesMap       map[string]bool
	IgnoreDirsMap  map[string]bool
	IgnoreBasesMap map[string]bool
	IgnoreTypesMap map[string]bool

	// TODO: consider
	MaxRune int
	Add     uint64
	Trim    bool
	Abort   bool

	nfiles uint64
	nlines uint64
}

// NewGotcha allocation for Gotcha
func NewGotcha() *Gotcha {
	makeBoolMap := func(list []string) map[string]bool {
		m := make(map[string]bool)
		for _, s := range list {
			m[s] = true
		}
		return m
	}
	return &Gotcha{
		W:   os.Stdout,
		Log: log.New(ioutil.Discard, "[todogotcha]:", log.Lshortfile),

		Word:           "TODO: ",
		TypesMap:       make(map[string]bool),
		IgnoreDirsMap:  makeBoolMap(IgnoreDirs),
		IgnoreBasesMap: makeBoolMap(IgnoreBases),
		IgnoreTypesMap: makeBoolMap(IgnoreTypes),

		MaxRune: 512,
		Add:     0,
		Trim:    false,
		Abort:   false,

		nfiles: 0,
		nlines: 0,
	}
}

// PrintTotal prnt nfiles and ncontents
func (g *Gotcha) PrintTotal() (int, error) {
	return fmt.Fprintf(g.W, "files %d\nlines %d\n", g.nfiles, g.nlines)
}

func (g *Gotcha) isTarget(path string) bool {
	if g.IgnoreBasesMap[path] {
		return false
	}
	ext := filepath.Ext(path)
	if g.IgnoreTypesMap[ext] {
		return false
	}
	if len(g.TypesMap) == 0 {
		return true
	}
	return g.TypesMap[ext]
}

// TODO: consider name
type gatherRes struct {
	path     string
	contents []string
	err      error
}

func (gr *gatherRes) Error() string {
	if gr.err == ErrHaveTooLongLine {
		return gr.err.Error() + ":" + gr.path
	}
	return gr.err.Error()
}

// ErrHaveTooLongLine read limit of over
var ErrHaveTooLongLine = errors.New("have too long line")

// IsTooLong check ErrHaveTooLongLine
func IsTooLong(err error) bool {
	switch e := err.(type) {
	case *gatherRes:
		return e.err == ErrHaveTooLongLine
	}
	return false
}

func (g *Gotcha) gather(path string) *gatherRes {
	gr := &gatherRes{path: path}
	var f *os.File
	f, gr.err = os.Open(path)
	if gr.err != nil {
		return gr
	}
	defer f.Close()

	sc := bufio.NewScanner(f)
	index := -1
	lineCount := uint64(1) // TODO: consider to zero
	addCount := uint64(0)

	var push func()
	if g.Trim {
		push = func() {
			gr.contents = append(gr.contents, fmt.Sprintf("L%v:%s", lineCount, sc.Text()[index+len(g.Word):]))
			addCount = 1
		}
	} else {
		push = func() {
			gr.contents = append(gr.contents, fmt.Sprintf("L%v:%s", lineCount, sc.Text()))
			addCount = 1
		}
	}

	var pushNextLines func()
	if g.Add != 0 {
		pushNextLines = func() {
			if addCount != 0 && addCount <= g.Add {
				gr.contents = append(gr.contents, fmt.Sprintf(" %v:%s", lineCount, sc.Text()))
				addCount++
			} else {
				addCount = 0
			}
		}
	} else {
		// discard
		pushNextLines = func() {}
	}

	for ; sc.Scan(); lineCount++ {
		if gr.err = sc.Err(); gr.err != nil {
			return gr
		}
		if g.MaxRune > 0 && len(sc.Text()) > g.MaxRune {
			gr.err = ErrHaveTooLongLine
			return gr
		}
		if index = strings.Index(sc.Text(), g.Word); index != -1 {
			push()
			continue
		}
		pushNextLines()
	}
	return gr
}

// WorkGo run on async
func (g *Gotcha) WorkGo(root string, nworker uint64) (exitCode int) {
	// queue -> gatherQueue -> res
	var (
		wg          = new(sync.WaitGroup)
		queue       = make(chan string, 512)
		gatherQueue = make(chan string, 512)
		res         = make(chan *gatherRes, 512)
		errch       = make(chan error, 128)
	)

	// TODO: consider really need? goCounter
	var (
		goCounter = uint64(0)
		done      = make(chan bool)
	)
	defer func() {
		for ; goCounter != 0; goCounter-- {
			done <- true
		}
	}()

	// TODO: consider
	if nworker == 0 {
		nworker = func() uint64 {
			n := runtime.NumCPU() / 2
			if n < 0 {
				return 0
			}
			return uint64(n)
		}()
	}

	// error handler
	// TODO: consider error handling
	//     : this is maybe discard some errors
	goCounter++
	go func() {
		for {
			select {
			case err := <-errch:
				// TODO: error handling
				if err != nil {
					exitCode = 1 // TODO: consider exitCode
					switch {
					case g.Abort:
						g.Log.Fatal(err) // TODO: consider
					case IsTooLong(err), os.IsPermission(err), os.IsNotExist(err):
						g.Log.Println(err)
						continue
					default:
						g.Log.Fatalln("unknown error:", err)
						//panic(err) // TODO: consider
					}
				}
			case <-done:
				return
			}
		}
	}()

	// woker
	for i := uint64(0); i <= nworker; i++ {
		goCounter++
		go func() {
			for {
				select {
				case path := <-gatherQueue:
					res <- g.gather(path)
				case <-done:
					return
				}
			}
		}()
	}

	// res with write
	goCounter++
	go func() {
		for {
			select {
			case gr := <-res:
				switch {
				case gr.err != nil:
					if gr.err == ErrHaveTooLongLine {
						errch <- gr
					} else {
						errch <- gr.err
					}
				case len(gr.contents) != 0:
					_, err := fmt.Fprintf(g.W, "%s\n%s\n\n", gr.path, strings.Join(gr.contents, "\n"))
					if err != nil {
						errch <- err
					}
					g.nfiles++
					g.nlines += uint64(len(gr.contents))
				}
				wg.Done()
			case <-done:
				return
			}
		}
	}()

	// walker
	goCounter++
	go func() {
		for {
			select {
			case dir := <-queue:
				infos, err := ioutil.ReadDir(dir)
				if err != nil {
					errch <- err
					wg.Done()
					continue
				}
				for _, info := range infos {
					path := filepath.Join(dir, info.Name())
					switch {
					case info.IsDir() && !g.IgnoreDirsMap[info.Name()]:
						// TODO: consider another way
						wg.Add(1)
						go func(path string) { queue <- path }(path)
						continue
					case info.Mode().IsRegular() && g.isTarget(info.Name()):
						wg.Add(1)
						gatherQueue <- path
						continue
					}
				}
				wg.Done()
			case <-done:
				return
			}
		}
	}()

	wg.Add(1)
	queue <- root
	wg.Wait()
	return exitCode
}

// SyncWorkGo run on sync
func (g *Gotcha) SyncWorkGo(root string) error {
	return filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if info.IsDir() && g.IgnoreDirsMap[info.Name()] {
			return filepath.SkipDir
		}
		if info.Mode().IsRegular() && g.isTarget(info.Name()) {
			gr := g.gather(path)
			if gr.err != nil {
				switch {
				case g.Abort:
					g.Log.Fatal(gr.err) // TODO: consider not use panic
				case IsTooLong(gr):
					g.Log.Print(gr)
				case os.IsPermission(gr.err) || os.IsNotExist(gr.err):
					g.Log.Print(gr.err)
				default:
					g.Log.Print(gr.err) // TODO: consider not use panic
				}
				return nil
			}
			if len(gr.contents) != 0 {
				_, err = fmt.Fprintf(g.W, "%s\n%s\n\n", gr.path, strings.Join(gr.contents, "\n"))
				g.nfiles++
				g.nlines += uint64(len(gr.contents))
			}
		}
		return err
	})
}
<|endoftext|>


<commit_before>package chlib

import (
	"encoding/json"
	"fmt"
	"os"
)

func LoadJsonFromFile(path string, b interface{}) (err error) {
	file, err := os.Open(path)
	if err != nil {
		return
	}
	err = json.NewDecoder(file).Decode(&b)
	return
}

func GetCmdRequestJson(client *Client, kind, name string) (ret []GenericJson, err error) {
	defer func() {
		if r := recover(); r != nil {
			err = fmt.Errorf("can`t extract field: %s", r)
		}
	}()
	var apiResult TcpApiResult
	switch kind {
	case KindNamespaces:
		apiResult, err = client.Get(KindNamespaces, name, "")
		if err != nil {
			return ret, err
		}
		items := apiResult["results"].([]interface{})
		for _, itemI := range items {
			item := itemI.(map[string]interface{})
			_, hasNs := item["data"].(map[string]interface{})["metadata"].(map[string]interface{})["namespace"]
			if hasNs {
				ret = append(ret, GenericJson(item))
			}
		}
	default:
		apiResult, err := client.Get(kind, name, client.userConfig.Namespace)
		if err != nil {
			return ret, err
		}
		items := apiResult["results"].([]interface{})
		for _, itemI := range items {
			ret = append(ret, itemI.(map[string]interface{}))
		}
	}
	return
}
<commit_msg>fix namespace print<commit_after>package chlib

import (
	"encoding/json"
	"fmt"
	"os"
)

func LoadJsonFromFile(path string, b interface{}) (err error) {
	file, err := os.Open(path)
	if err != nil {
		return
	}
	err = json.NewDecoder(file).Decode(&b)
	return
}

func GetCmdRequestJson(client *Client, kind, name string) (ret []GenericJson, err error) {
	defer func() {
		if r := recover(); r != nil {
			err = fmt.Errorf("can`t extract field: %s", r)
		}
	}()
	apiResult, err := client.Get(kind, name, client.userConfig.Namespace)
	if err != nil {
		return ret, err
	}
	items := apiResult["results"].([]interface{})
	for _, itemI := range items {
		ret = append(ret, itemI.(map[string]interface{}))
	}
	return
}
<|endoftext|>


<commit_before>package engine

import (
	"container/ring"
	"fmt"
	"strconv"
	"sync"

	"github.com/sai-lab/mouryou/lib/convert"
	"github.com/sai-lab/mouryou/lib/logger"
	"github.com/sai-lab/mouryou/lib/models"
	"github.com/sai-lab/mouryou/lib/monitor"
	"github.com/sai-lab/mouryou/lib/mutex"
	"github.com/sai-lab/mouryou/lib/predictions"
)

// ServerManagement は起動状況と負荷状況に基いてオートスケールを実行します.
// 起動状況はengine.destination_settingが設定しています.
// 負荷状況はmonitor.LoadChから取得します.
func ServerManagement(c *models.Config) {
	var (
		// totalOR means the total value of the operating ratios of the working servers
		totalOR float64
		// w means the number of working servers
		w int
		// b means the number of booting servers
		b int
		// s means the number of servers that are stopped
		s int
		// tw means the total value of the weights of the working servers
		tw int
		// nw means the necessary weights
		nw int
	)

	r := ring.New(LING_SIZE)
	ttlORs := make([]float64, LING_SIZE)

	for totalOR = range monitor.LoadCh {
		r.Value = totalOR
		r = r.Next()
		ttlORs = convert.RingToArray(r)

		// Get Number of Active Servers
		w = mutex.Read(&working, &workMutex)
		b = mutex.Read(&booting, &bootMutex)
		s = mutex.Read(&shuting, &shutMutex)
		tw = mutex.Read(&totalWeight, &totalWeightMutex)

		// Exec Algorithm
		if c.UseHetero {
			nw = predictions.ExecDifferentAlgorithm(c, w, b, s, tw, ttlORs)
			switch {
			case nw > tw:
				go bootUpVMs(c, nw-tw)
			case nw < tw:
				go shutDownVMs(c, tw-nw)
			}
		} else {
			startStopSameServers(c, ttlORs, w, b, s, tw)
		}
	}
}

// startStopSameServersは単一性能向けアルゴリズムのサーバ起動停止メソッドです.
// predictions.ExecSameAlgorithmメソッドからmodels.Config.Sleep時間後に必要な台数と
// スケールインするかの真偽値を受け取り,それらに従って起動停止処理を実行します.
func startStopSameServers(c *models.Config, ttlORs []float64, w int, b int, s int, tw int) {
	var (
		scaleIn        bool
		requiredNumber float64
		i              int
	)

	requiredNumber, scaleIn = predictions.ExecSameAlgorithm(c, w, b, s, tw, ttlORs)

	if c.DevelopLogLevel >= 1 {
		logger.PrintPlace("required server num is " + strconv.Itoa(int(requiredNumber)))
	}
	switch {
	case w+b < len(c.Cluster.VirtualMachines) && int(requiredNumber) > 0 && s == 0:
		for i = 0; i < int(requiredNumber); i++ {
			if w+b+i < len(c.Cluster.VirtualMachines) {
				if c.DevelopLogLevel >= 1 {
					logger.PrintPlace("w + b + i " + strconv.Itoa(w+b+i) + " VM len " + strconv.Itoa(len(c.Cluster.VirtualMachines)))
				}
				for _, status := range monitor.GetStates() {
					if status.Info != "shutted down" {
						continue
					}
					go bootUpVM(c, status)
					mutex.Write(&totalWeight, &totalWeightMutex, totalWeight+status.Weight)
					if c.DevelopLogLevel >= 1 {
						logger.PrintPlace("BootUp " + status.Name)
					}
					break
				}
			}
		}
	case w > 1 && scaleIn && mutex.Read(&waiting, &waitMutex) == 0 && b == 0:
		go shutDownVMs(c, 10)
		if c.DevelopLogLevel >= 1 {
			fmt.Println("working number is " + strconv.Itoa(w))
			fmt.Println("SM: Shutdown is fired")
		}
	}
}

// bootUpVMs
func bootUpVMs(c *models.Config, weight int) {
	var candidate []int

	statuses := monitor.GetStates()

	for i, status := range statuses {
		// 停止中のサーバ以外は無視
		if status.Info != "shutted down" {
			continue
		}
		if status.Weight >= weight {
			go bootUpVM(c, status)
			mutex.Write(&totalWeight, &totalWeightMutex, totalWeight+status.Weight)
			return
		}
		candidate = append(candidate, i)
	}

	if len(candidate) == 0 {
		return
	}

	boot := candidate[0]
	for _, n := range candidate {
		if statuses[n].Weight > statuses[boot].Weight {
			boot = n
		}
	}
	go bootUpVM(c, statuses[boot])
	mutex.Write(&totalWeight, &totalWeightMutex, totalWeight+statuses[boot].Weight)
}

// bootUpVM
func bootUpVM(c *models.Config, st monitor.State) {
	var p monitor.PowerStruct

	p.Name = st.Name
	p.Info = "booting up"
	st.Info = "booting up"
	if monitor.PowerCh != nil {
		monitor.PowerCh <- p
	}
	if monitor.StateCh != nil {
		monitor.StateCh <- st
	}
	if c.DevelopLogLevel >= 1 {
		fmt.Println(st.Name + " is booting up")
	}

	p.Info = c.Cluster.VirtualMachines[st.Name].Bootup(c.Sleep)
	st.Info = p.Info
	if monitor.PowerCh != nil {
		monitor.PowerCh <- p
	}
	if monitor.StateCh != nil {
		monitor.StateCh <- st
	}
	if c.DevelopLogLevel >= 1 {
		fmt.Println(st.Name + " is boot up")
	}
}

// shutDownVMs
func shutDownVMs(c *models.Config, weight int) {
	var mu sync.RWMutex

	mu.RLock()
	defer mu.RUnlock()

	for _, st := range monitor.States {
		// 稼働中のサーバ以外は無視
		if st.Info != "booted up" {
			continue
		}
		// オリジンサーバは無視
		if c.ContainMachineName(c.OriginMachineNames, st.Name) {
			continue
		}
		// 常に稼働するサーバは無視
		if c.ContainMachineName(c.AlwaysRunningMachines, st.Name) {
			continue
		}

		if st.Weight <= weight {
			go shutDownVM(c, st)
			mutex.Write(&totalWeight, &totalWeightMutex, totalWeight-st.Weight)
			if c.DevelopLogLevel >= 1 {
				fmt.Println(st.Name + " going to shutdown")
			}
			return
		}
	}
}

//shutDownVM
func shutDownVM(c *models.Config, st monitor.State) {
	var p monitor.PowerStruct
	p.Name = st.Name
	p.Info = "shutting down"
	st.Info = "shutting down"
	if monitor.PowerCh != nil {
		monitor.PowerCh <- p
	}
	if monitor.StateCh != nil {
		monitor.StateCh <- st
	}

	p.Info = c.Cluster.VirtualMachines[st.Name].Shutdown(c.Sleep)
	st.Info = p.Info
	if monitor.PowerCh != nil {
		monitor.PowerCh <- p
	}
	if monitor.StateCh != nil {
		monitor.StateCh <- st
	}
}
<commit_msg>server_managementでのboot up処理を修正<commit_after>package engine

import (
	"container/ring"
	"fmt"
	"strconv"
	"sync"

	"github.com/sai-lab/mouryou/lib/convert"
	"github.com/sai-lab/mouryou/lib/logger"
	"github.com/sai-lab/mouryou/lib/models"
	"github.com/sai-lab/mouryou/lib/monitor"
	"github.com/sai-lab/mouryou/lib/mutex"
	"github.com/sai-lab/mouryou/lib/predictions"
)

// ServerManagement は起動状況と負荷状況に基いてオートスケールを実行します.
// 起動状況はengine.destination_settingが設定しています.
// 負荷状況はmonitor.LoadChから取得します.
func ServerManagement(c *models.Config) {
	var (
		// totalOR means the total value of the operating ratios of the working servers
		totalOR float64
		// w means the number of working servers
		w int
		// b means the number of booting servers
		b int
		// s means the number of servers that are stopped
		s int
		// tw means the total value of the weights of the working servers
		tw int
		// nw means the necessary weights
		nw int
	)

	r := ring.New(LING_SIZE)
	ttlORs := make([]float64, LING_SIZE)

	for totalOR = range monitor.LoadCh {
		r.Value = totalOR
		r = r.Next()
		ttlORs = convert.RingToArray(r)

		// Get Number of Active Servers
		w = mutex.Read(&working, &workMutex)
		b = mutex.Read(&booting, &bootMutex)
		s = mutex.Read(&shuting, &shutMutex)
		tw = mutex.Read(&totalWeight, &totalWeightMutex)

		// Exec Algorithm
		if c.UseHetero {
			nw = predictions.ExecDifferentAlgorithm(c, w, b, s, tw, ttlORs)
			switch {
			case nw > tw:
				go bootUpVMs(c, nw-tw)
			case nw < tw:
				go shutDownVMs(c, tw-nw)
			}
		} else {
			startStopSameServers(c, ttlORs, w, b, s, tw)
		}
	}
}

// startStopSameServersは単一性能向けアルゴリズムのサーバ起動停止メソッドです.
// predictions.ExecSameAlgorithmメソッドからmodels.Config.Sleep時間後に必要な台数と
// スケールインするかの真偽値を受け取り,それらに従って起動停止処理を実行します.
func startStopSameServers(c *models.Config, ttlORs []float64, w int, b int, s int, tw int) {
	var (
		scaleIn        bool
		requiredNumber float64
	)

	requiredNumber, scaleIn = predictions.ExecSameAlgorithm(c, w, b, s, tw, ttlORs)

	if c.DevelopLogLevel >= 1 {
		logger.PrintPlace("required server num is " + strconv.Itoa(int(requiredNumber)))
	}
	switch {
	case w+b < len(c.Cluster.VirtualMachines) && int(requiredNumber) > 0 && s == 0:
		i := 0
		for _, status := range monitor.GetStates() {
			if status.Info == "shutted down" && w+b+i < len(c.Cluster.VirtualMachines) && i < int(requiredNumber) {
				go bootUpVM(c, status)
				mutex.Write(&totalWeight, &totalWeightMutex, totalWeight+status.Weight)
				if c.DevelopLogLevel >= 1 {
					logger.PrintPlace("BootUp " + status.Name)
				}
			}
			i++
		}
		// for i = 0; i < int(requiredNumber); i++ {
		// 	if w+b+i < len(c.Cluster.VirtualMachines) {
		// 		if c.DevelopLogLevel >= 1 {
		// 			logger.PrintPlace("w+b+i " + strconv.Itoa(w+b+i) + " VM len " + strconv.Itoa(len(c.Cluster.VirtualMachines)))
		// 		}
		// 		for _, status := range monitor.GetStates() {
		// 			if status.Info != "shutted down" {
		// 				continue
		// 			}
		// 			go bootUpVM(c, status)
		// 			mutex.Write(&totalWeight, &totalWeightMutex, totalWeight+status.Weight)
		// 			if c.DevelopLogLevel >= 1 {
		// 				logger.PrintPlace("BootUp " + status.Name)
		// 			}
		// 			break
		// 		}
		// 	}
		// }
	case w > 1 && scaleIn && mutex.Read(&waiting, &waitMutex) == 0 && b == 0:
		go shutDownVMs(c, 10)
		if c.DevelopLogLevel >= 1 {
			fmt.Println("working number is " + strconv.Itoa(w))
			fmt.Println("SM: Shutdown is fired")
		}
	}
}

// bootUpVMs
func bootUpVMs(c *models.Config, weight int) {
	var candidate []int

	statuses := monitor.GetStates()

	for i, status := range statuses {
		// 停止中のサーバ以外は無視
		if status.Info != "shutted down" {
			continue
		}
		if status.Weight >= weight {
			go bootUpVM(c, status)
			mutex.Write(&totalWeight, &totalWeightMutex, totalWeight+status.Weight)
			return
		}
		candidate = append(candidate, i)
	}

	if len(candidate) == 0 {
		return
	}

	boot := candidate[0]
	for _, n := range candidate {
		if statuses[n].Weight > statuses[boot].Weight {
			boot = n
		}
	}
	go bootUpVM(c, statuses[boot])
	mutex.Write(&totalWeight, &totalWeightMutex, totalWeight+statuses[boot].Weight)
}

// bootUpVM
func bootUpVM(c *models.Config, st monitor.State) {
	var p monitor.PowerStruct

	p.Name = st.Name
	p.Info = "booting up"
	st.Info = "booting up"
	if monitor.PowerCh != nil {
		monitor.PowerCh <- p
	}
	if monitor.StateCh != nil {
		monitor.StateCh <- st
	}
	if c.DevelopLogLevel >= 1 {
		fmt.Println(st.Name + " is booting up")
	}

	p.Info = c.Cluster.VirtualMachines[st.Name].Bootup(c.Sleep)
	st.Info = p.Info
	if monitor.PowerCh != nil {
		monitor.PowerCh <- p
	}
	if monitor.StateCh != nil {
		monitor.StateCh <- st
	}
	if c.DevelopLogLevel >= 1 {
		fmt.Println(st.Name + " is boot up")
	}
}

// shutDownVMs
func shutDownVMs(c *models.Config, weight int) {
	var mu sync.RWMutex

	mu.RLock()
	defer mu.RUnlock()

	for _, st := range monitor.States {
		// 稼働中のサーバ以外は無視
		if st.Info != "booted up" {
			continue
		}
		// オリジンサーバは無視
		if c.ContainMachineName(c.OriginMachineNames, st.Name) {
			continue
		}
		// 常に稼働するサーバは無視
		if c.ContainMachineName(c.AlwaysRunningMachines, st.Name) {
			continue
		}

		if st.Weight <= weight {
			go shutDownVM(c, st)
			mutex.Write(&totalWeight, &totalWeightMutex, totalWeight-st.Weight)
			if c.DevelopLogLevel >= 1 {
				fmt.Println(st.Name + " going to shutdown")
			}
			return
		}
	}
}

//shutDownVM
func shutDownVM(c *models.Config, st monitor.State) {
	var p monitor.PowerStruct
	p.Name = st.Name
	p.Info = "shutting down"
	st.Info = "shutting down"
	if monitor.PowerCh != nil {
		monitor.PowerCh <- p
	}
	if monitor.StateCh != nil {
		monitor.StateCh <- st
	}

	p.Info = c.Cluster.VirtualMachines[st.Name].Shutdown(c.Sleep)
	st.Info = p.Info
	if monitor.PowerCh != nil {
		monitor.PowerCh <- p
	}
	if monitor.StateCh != nil {
		monitor.StateCh <- st
	}
}
<|endoftext|>


<commit_before>// +build integration

package client

import (
	"time"
	"testing"

	"github.com/dnaeon/gru/minion"

	"golang.org/x/net/context"
	etcdclient "github.com/coreos/etcd/client"
)

// Default config for etcd minions and clients
var defaultEtcdConfig = etcdclient.Config{
	Endpoints:               []string{"http://127.0.0.1:2379", "http:127.0.0.1:4001"},
	Transport:               etcdclient.DefaultTransport,
	HeaderTimeoutPerRequest: time.Second,
}

// Cleans up the minion space in etcd after tests
func cleanupAfterTest(t *testing.T) {
	c, err := etcdclient.New(defaultEtcdConfig)
	if err != nil {
		t.Fatal(err)
	}

	kapi := etcdclient.NewKeysAPI(c)
	deleteOpts := &etcdclient.DeleteOptions{
		Recursive: true,
		Dir: true,
	}

	_, err = kapi.Delete(context.Background(), minion.EtcdMinionSpace, deleteOpts)
	if err != nil {
		t.Fatal(err)
	}
}

func TestMinionList(t *testing.T) {
	defer cleanupAfterTest(t)

	minions := []minion.Minion{
		minion.NewEtcdMinion("Bob", defaultEtcdConfig),
		minion.NewEtcdMinion("Kevin", defaultEtcdConfig),
		minion.NewEtcdMinion("Stuart", defaultEtcdConfig),
	}

	// Start our minions
	for _, m := range minions {
		m.Serve()
		defer m.Stop()
	}
	time.Sleep(time.Second)

	klient := NewEtcdMinionClient(defaultEtcdConfig)
	minionList, err := klient.MinionList()
	if err != nil {
		t.Fatal(err)
	}

	want := len(minions)
	got := len(minionList)

	if want != got {
		t.Errorf("want %d minion, got %d minion(s)", want, got)
	}
}

func TestMinionName(t *testing.T) {
	defer cleanupAfterTest(t)

	wantName := "Kevin"
	m := minion.NewEtcdMinion(wantName, defaultEtcdConfig)
	minionId := m.ID()
	m.Serve()
	defer m.Stop()
	time.Sleep(time.Second)

	klient := NewEtcdMinionClient(defaultEtcdConfig)
	gotName, err := klient.MinionName(minionId)
	if err != nil {
		t.Fatal(err)
	}

	if wantName != gotName {
		t.Errorf("want %q, got %q", wantName, gotName)
	}
}

func TestMinionLastseen(t *testing.T) {
	defer cleanupAfterTest(t)

	m := minion.NewEtcdMinion("Kevin", defaultEtcdConfig)
	id := m.ID()
	want := time.Now().Unix()
	err := m.SetLastseen(want)
	if err != nil {
		t.Fatal(err)
	}

	klient := NewEtcdMinionClient(defaultEtcdConfig)
	got, err := klient.MinionLastseen(id)

	if want != got {
		t.Errorf("want %d, got %d", want, got)
	}
}
<commit_msg>tests: cleanup after tests once all minions have been stopped<commit_after>// +build integration

package client

import (
	"time"
	"testing"

	"github.com/dnaeon/gru/minion"

	"golang.org/x/net/context"
	etcdclient "github.com/coreos/etcd/client"
)

// Default config for etcd minions and clients
var defaultEtcdConfig = etcdclient.Config{
	Endpoints:               []string{"http://127.0.0.1:2379", "http:127.0.0.1:4001"},
	Transport:               etcdclient.DefaultTransport,
	HeaderTimeoutPerRequest: time.Second,
}

// Cleans up the minion space in etcd after tests
func cleanupAfterTest(t *testing.T) {
	c, err := etcdclient.New(defaultEtcdConfig)
	if err != nil {
		t.Fatal(err)
	}

	kapi := etcdclient.NewKeysAPI(c)
	deleteOpts := &etcdclient.DeleteOptions{
		Recursive: true,
		Dir: true,
	}

	_, err = kapi.Delete(context.Background(), minion.EtcdMinionSpace, deleteOpts)
	if err != nil {
		t.Fatal(err)
	}
}

func TestMinionList(t *testing.T) {
	minions := []minion.Minion{
		minion.NewEtcdMinion("Bob", defaultEtcdConfig),
		minion.NewEtcdMinion("Kevin", defaultEtcdConfig),
		minion.NewEtcdMinion("Stuart", defaultEtcdConfig),
	}

	// Start our minions
	for _, m := range minions {
		m.Serve()
		defer m.Stop()
	}
	defer cleanupAfterTest(t)

	klient := NewEtcdMinionClient(defaultEtcdConfig)
	minionList, err := klient.MinionList()
	if err != nil {
		t.Fatal(err)
	}

	want := len(minions)
	got := len(minionList)

	if want != got {
		t.Errorf("want %d minion, got %d minion(s)", want, got)
	}
}

func TestMinionName(t *testing.T) {
	wantName := "Kevin"
	m := minion.NewEtcdMinion(wantName, defaultEtcdConfig)
	minionId := m.ID()
	m.Serve()
	defer m.Stop()
	defer cleanupAfterTest(t)

	klient := NewEtcdMinionClient(defaultEtcdConfig)
	gotName, err := klient.MinionName(minionId)
	if err != nil {
		t.Fatal(err)
	}

	if wantName != gotName {
		t.Errorf("want %q, got %q", wantName, gotName)
	}
}

func TestMinionLastseen(t *testing.T) {
	defer cleanupAfterTest(t)

	m := minion.NewEtcdMinion("Kevin", defaultEtcdConfig)
	id := m.ID()
	want := time.Now().Unix()
	err := m.SetLastseen(want)
	if err != nil {
		t.Fatal(err)
	}

	klient := NewEtcdMinionClient(defaultEtcdConfig)
	got, err := klient.MinionLastseen(id)

	if want != got {
		t.Errorf("want %d, got %d", want, got)
	}
}
<|endoftext|>


<commit_before>package client

import (
	"github.com/gopherjs/jquery"
)

//NarrowDom is a narrow interface to accessing the DOM that can be
//simulated for test purposes.
type NarrowDom interface {
	SetData(string, string)
	Data(string) string
	RemoveData(string)
	Css(string) string
	SetCss(string, string)
	Text() string
	SetText(string)
	Attr(string) string
	SetAttr(string, string)
	Prop(string) bool
	SetProp(string, bool)
	On(EventName, EventFunc)
	Trigger(EventName)
	HasClass(string) bool
	AddClass(string)
	RemoveClass(string)
	Val() string
	SetVal(string)
	Append(NarrowDom)
	Before(NarrowDom)
}

type jqueryWrapper struct {
	jq jquery.JQuery
}

func wrap(j jquery.JQuery) NarrowDom {
	return jqueryWrapper{j}
}

type testOpsImpl struct {
	data     map[string]string
	css      map[string]string
	text     string
	val      string
	attr     map[string]string
	prop     map[string]bool
	radio    map[string]string
	classes  map[string]int
	event    map[EventName]EventFunc
	parent   *testOpsImpl //need the nil
	children []*testOpsImpl
}

func newTestOps() NarrowDom {
	result := testOpsImpl{
		data:    make(map[string]string),
		css:     make(map[string]string),
		attr:    make(map[string]string),
		prop:    make(map[string]bool),
		classes: make(map[string]int),
		event:   make(map[EventName]EventFunc),
	}
	return &result
}

func (self *testOpsImpl) SetData(k string, v string) {
	self.data[k] = v
}

func (self jqueryWrapper) SetData(k string, v string) {
	self.jq.SetData(k, v)
}

func (self *testOpsImpl) RemoveData(k string) {
	delete(self.data, k)
}

func (self jqueryWrapper) RemoveData(k string) {
	self.jq.RemoveData(k)
}

func (self *testOpsImpl) Data(k string) string {
	return self.data[k]
}

func (self jqueryWrapper) Data(k string) string {
	i := self.jq.Data(k)
	if i == nil {
		return ""
	}
	return i.(string)
}

func (self *testOpsImpl) Css(k string) string {
	return self.css[k]
}
func (self jqueryWrapper) Css(k string) string {
	return self.jq.Css(k)
}

func (self *testOpsImpl) SetCss(k string, v string) {
	self.css[k] = v
}
func (self jqueryWrapper) SetCss(k string, v string) {
	self.jq.SetCss(k, v)
}

func (self *testOpsImpl) Text() string {
	return self.text
}

func (self jqueryWrapper) Text() string {
	return self.jq.Text()
}

func (self *testOpsImpl) SetText(v string) {
	self.text = v
}

func (self jqueryWrapper) SetText(v string) {
	self.jq.SetText(v)
}

func (self *testOpsImpl) Attr(k string) string {
	return self.attr[k]
}
func (self jqueryWrapper) Attr(k string) string {
	return self.jq.Attr(k)
}

func (self *testOpsImpl) SetAttr(k string, v string) {
	self.attr[k] = v
}
func (self jqueryWrapper) SetAttr(k string, v string) {
	self.jq.SetAttr(k, v)
}

func (self *testOpsImpl) Prop(k string) bool {
	return self.prop[k]
}
func (self jqueryWrapper) Prop(k string) bool {
	return self.jq.Prop(k).(bool)
}

func (self *testOpsImpl) SetProp(k string, v bool) {
	self.prop[k] = v
}
func (self jqueryWrapper) SetProp(k string, v bool) {
	self.jq.SetProp(k, v)
}

func (self *testOpsImpl) On(name EventName, fn EventFunc) {
	self.event[name] = fn
}

func (self jqueryWrapper) On(n EventName, fn EventFunc) {
	handler := eventHandler{
		name: n,
		fn:   fn,
		t:    self,
	}
	self.jq.On(n.String(), handler.handle)
}

func (self *testOpsImpl) Trigger(name EventName) {
	fn, ok := self.event[name]
	if ok {
		handler := eventHandler{
			fn:   fn,
			name: name,
			t:    self,
		}
		handler.handle(jquery.Event{Type: name.String()})
	}
}

func (self jqueryWrapper) Trigger(n EventName) {
	self.jq.Trigger(n.String())
}

func (self *testOpsImpl) HasClass(k string) bool {
	_, ok := self.classes[k]
	return ok
}

func (self jqueryWrapper) HasClass(k string) bool {
	return self.jq.HasClass(k)
}

func (self *testOpsImpl) Val() string {
	return self.val
}

func (self jqueryWrapper) Val() string {
	v := self.jq.Val()
	return v
}

func (self *testOpsImpl) SetVal(s string) {
	self.val = s
}

func (self jqueryWrapper) SetVal(s string) {
	self.jq.SetVal(s)
}

func (self *testOpsImpl) AddClass(s string) {
	self.classes[s] = 0
}

func (self jqueryWrapper) AddClass(s string) {
	self.jq.AddClass(s)
}

func (self *testOpsImpl) RemoveClass(s string) {
	delete(self.classes, s)
}

func (self jqueryWrapper) RemoveClass(s string) {
	self.jq.RemoveClass(s)
}

func (self *testOpsImpl) Append(nd NarrowDom) {
	child := nd.(*testOpsImpl)
	if child.parent != nil {
		panic("can't add a child, it already has a parent!")
	}
	child.parent = self
	self.children = append(self.children, child)
}

func (self jqueryWrapper) Append(nd NarrowDom) {
	wrapper := nd.(jqueryWrapper)
	self.jq.Append(wrapper.jq)
}

func (self *testOpsImpl) Before(nd NarrowDom) {
	child := nd.(*testOpsImpl)
	parent := child.parent
	done := false
	for i, cand := range parent.children {
		if cand == child {
			rest := parent.children[i:]
			parent.children = append(parent.children[0:i], child)
			parent.children = append(parent.children, rest...)
			done = true
			break
		}
	}
	if !done {
		panic("unable to find child to insert before!")
	}
}

func (self jqueryWrapper) Before(nd NarrowDom) {
	wrapper := nd.(jqueryWrapper)
	self.jq.Before(wrapper.jq)
}

func (self *testOpsImpl) SetRadioButton(groupName string, value string) {
	self.radio[groupName] = value
}

func (self *testOpsImpl) RadioButton(groupName string) string {
	return self.radio[groupName]
}

func (self jqueryWrapper) SetRadioButton(groupName string, value string) {
	selector := "input[name=\"" + groupName + "\"][type=\"radio\"]"
	print("selector is ", selector)
	jq := jquery.NewJQuery(selector)
	jq.SetVal(value)
}

func (self jqueryWrapper) RadioButton(groupName string) string {
	selector := "input[name=\"" + groupName + "\"][type=\"radio\"]" + ":checked"
	print("selector is ", selector)
	jq := jquery.NewJQuery(selector)
	return jq.Val()
}
<commit_msg>added clear and made append take varargs<commit_after>package client

import (
	"github.com/gopherjs/jquery"
)

//NarrowDom is a narrow interface to accessing the DOM that can be
//simulated for test purposes.
type NarrowDom interface {
	SetData(string, string)
	Data(string) string
	RemoveData(string)
	Css(string) string
	SetCss(string, string)
	Text() string
	SetText(string)
	Attr(string) string
	SetAttr(string, string)
	Prop(string) bool
	SetProp(string, bool)
	On(EventName, EventFunc)
	Trigger(EventName)
	HasClass(string) bool
	AddClass(string)
	RemoveClass(string)
	Val() string
	SetVal(string)
	Clear()
	Append(...NarrowDom)
	Before(NarrowDom)
}

type jqueryWrapper struct {
	jq jquery.JQuery
}

func wrap(j jquery.JQuery) NarrowDom {
	return jqueryWrapper{j}
}

type testOpsImpl struct {
	data     map[string]string
	css      map[string]string
	text     string
	val      string
	attr     map[string]string
	prop     map[string]bool
	radio    map[string]string
	classes  map[string]int
	event    map[EventName]EventFunc
	parent   *testOpsImpl //need the nil
	children []*testOpsImpl
}

func newTestOps() NarrowDom {
	result := testOpsImpl{
		data:    make(map[string]string),
		css:     make(map[string]string),
		attr:    make(map[string]string),
		prop:    make(map[string]bool),
		classes: make(map[string]int),
		event:   make(map[EventName]EventFunc),
	}
	return &result
}

func (self *testOpsImpl) SetData(k string, v string) {
	self.data[k] = v
}

func (self jqueryWrapper) SetData(k string, v string) {
	self.jq.SetData(k, v)
}

func (self *testOpsImpl) RemoveData(k string) {
	delete(self.data, k)
}

func (self jqueryWrapper) RemoveData(k string) {
	self.jq.RemoveData(k)
}

func (self *testOpsImpl) Data(k string) string {
	return self.data[k]
}

func (self jqueryWrapper) Data(k string) string {
	i := self.jq.Data(k)
	if i == nil {
		return ""
	}
	return i.(string)
}

func (self *testOpsImpl) Css(k string) string {
	return self.css[k]
}
func (self jqueryWrapper) Css(k string) string {
	return self.jq.Css(k)
}

func (self *testOpsImpl) SetCss(k string, v string) {
	self.css[k] = v
}
func (self jqueryWrapper) SetCss(k string, v string) {
	self.jq.SetCss(k, v)
}

func (self *testOpsImpl) Text() string {
	return self.text
}

func (self jqueryWrapper) Text() string {
	return self.jq.Text()
}

func (self *testOpsImpl) SetText(v string) {
	self.text = v
}

func (self jqueryWrapper) SetText(v string) {
	self.jq.SetText(v)
}

func (self *testOpsImpl) Attr(k string) string {
	return self.attr[k]
}
func (self jqueryWrapper) Attr(k string) string {
	return self.jq.Attr(k)
}

func (self *testOpsImpl) SetAttr(k string, v string) {
	self.attr[k] = v
}
func (self jqueryWrapper) SetAttr(k string, v string) {
	self.jq.SetAttr(k, v)
}

func (self *testOpsImpl) Prop(k string) bool {
	return self.prop[k]
}
func (self jqueryWrapper) Prop(k string) bool {
	return self.jq.Prop(k).(bool)
}

func (self *testOpsImpl) SetProp(k string, v bool) {
	self.prop[k] = v
}
func (self jqueryWrapper) SetProp(k string, v bool) {
	self.jq.SetProp(k, v)
}

func (self *testOpsImpl) On(name EventName, fn EventFunc) {
	self.event[name] = fn
}

func (self jqueryWrapper) On(n EventName, fn EventFunc) {
	handler := eventHandler{
		name: n,
		fn:   fn,
		t:    self,
	}
	self.jq.On(n.String(), handler.handle)
}

func (self *testOpsImpl) Trigger(name EventName) {
	fn, ok := self.event[name]
	if ok {
		handler := eventHandler{
			fn:   fn,
			name: name,
			t:    self,
		}
		handler.handle(jquery.Event{Type: name.String()})
	}
}

func (self jqueryWrapper) Trigger(n EventName) {
	self.jq.Trigger(n.String())
}

func (self *testOpsImpl) HasClass(k string) bool {
	_, ok := self.classes[k]
	return ok
}

func (self jqueryWrapper) HasClass(k string) bool {
	return self.jq.HasClass(k)
}

func (self *testOpsImpl) Val() string {
	return self.val
}

func (self jqueryWrapper) Val() string {
	v := self.jq.Val()
	return v
}

func (self *testOpsImpl) SetVal(s string) {
	self.val = s
}

func (self jqueryWrapper) SetVal(s string) {
	self.jq.SetVal(s)
}

func (self *testOpsImpl) AddClass(s string) {
	self.classes[s] = 0
}

func (self jqueryWrapper) AddClass(s string) {
	self.jq.AddClass(s)
}

func (self *testOpsImpl) RemoveClass(s string) {
	delete(self.classes, s)
}

func (self jqueryWrapper) RemoveClass(s string) {
	self.jq.RemoveClass(s)
}
func (self *testOpsImpl) Clear() {
	self.children = make([]*testOpsImpl, 10)
}
func (self jqueryWrapper) Clear() {
	self.jq.Empty()
}

func (self *testOpsImpl) Append(childrennd ...NarrowDom) {
	for _, nd := range childrennd {
		child := nd.(*testOpsImpl)
		if child.parent != nil {
			panic("can't add a child, it already has a parent!")
		}
		child.parent = self
		self.children = append(self.children, child)
	}
}

func (self jqueryWrapper) Append(childrennd ...NarrowDom) {
	for _, nd := range childrennd {
		wrapper := nd.(jqueryWrapper)
		self.jq.Append(wrapper.jq)
	}
}

func (self *testOpsImpl) Before(nd NarrowDom) {
	child := nd.(*testOpsImpl)
	parent := child.parent
	done := false
	for i, cand := range parent.children {
		if cand == child {
			rest := parent.children[i:]
			parent.children = append(parent.children[0:i], child)
			parent.children = append(parent.children, rest...)
			done = true
			break
		}
	}
	if !done {
		panic("unable to find child to insert before!")
	}
}

func (self jqueryWrapper) Before(nd NarrowDom) {
	wrapper := nd.(jqueryWrapper)
	self.jq.Before(wrapper.jq)
}

func (self *testOpsImpl) SetRadioButton(groupName string, value string) {
	self.radio[groupName] = value
}

func (self *testOpsImpl) RadioButton(groupName string) string {
	return self.radio[groupName]
}

func (self jqueryWrapper) SetRadioButton(groupName string, value string) {
	selector := "input[name=\"" + groupName + "\"][type=\"radio\"]"
	print("selector is ", selector)
	jq := jquery.NewJQuery(selector)
	jq.SetVal(value)
}

func (self jqueryWrapper) RadioButton(groupName string) string {
	selector := "input[name=\"" + groupName + "\"][type=\"radio\"]" + ":checked"
	print("selector is ", selector)
	jq := jquery.NewJQuery(selector)
	return jq.Val()
}
<|endoftext|>


<commit_before>package nc

import (
	"time"

	"github.com/CyCoreSystems/ari"
	"github.com/nats-io/nats"
)

// DefaultRequestTimeout is the default timeout for a NATS request
const DefaultRequestTimeout = 20 * time.Millisecond

// Options is the list options
type Options struct {

	// URL is the nats URL
	URL string

	// ReadOperationRetryCount is the amount of times to retry a read operation
	ReadOperationRetryCount int

	// RequestTimeout is the timeout duration of a request
	RequestTimeout time.Duration
}

// New creates a new ari.Client connected to a gateway ARI server via NATS
func New(opts Options) (cl *ari.Client, err error) {

	var nc *nats.Conn
	nc, err = nats.Connect(opts.URL)
	if err != nil {
		return
	}

	if opts.RequestTimeout == 0 {
		opts.RequestTimeout = DefaultRequestTimeout
	}

	conn := &Conn{
		opts: opts,
		conn: nc,
	}

	playback := natsPlayback{conn}
	bus := &natsBus{conn}
	liveRecording := &natsLiveRecording{conn}
	storedRecording := &natsStoredRecording{conn}
	logging := &natsLogging{conn}
	modules := &natsModules{conn}

	cl = &ari.Client{
		Cleanup:     func() error { nc.Close(); return nil },
		Asterisk:    &natsAsterisk{conn, logging, modules},
		Application: &natsApplication{conn},
		Bridge:      &natsBridge{conn, &playback, liveRecording},
		Channel:     &natsChannel{conn, &playback, liveRecording},
		DeviceState: &natsDeviceState{conn},
		Mailbox:     &natsMailbox{conn},
		Sound:       &natsSound{conn},
		Playback:    &playback,
		Recording: &ari.Recording{
			Live:   liveRecording,
			Stored: storedRecording,
		},
		Bus: bus,
	}

	return
}
<commit_msg>nats - increase default timeout to 200ms<commit_after>package nc

import (
	"time"

	"github.com/CyCoreSystems/ari"
	"github.com/nats-io/nats"
)

// DefaultRequestTimeout is the default timeout for a NATS request
const DefaultRequestTimeout = 200 * time.Millisecond

// Options is the list options
type Options struct {

	// URL is the nats URL
	URL string

	// ReadOperationRetryCount is the amount of times to retry a read operation
	ReadOperationRetryCount int

	// RequestTimeout is the timeout duration of a request
	RequestTimeout time.Duration
}

// New creates a new ari.Client connected to a gateway ARI server via NATS
func New(opts Options) (cl *ari.Client, err error) {

	var nc *nats.Conn
	nc, err = nats.Connect(opts.URL)
	if err != nil {
		return
	}

	if opts.RequestTimeout == 0 {
		opts.RequestTimeout = DefaultRequestTimeout
	}

	conn := &Conn{
		opts: opts,
		conn: nc,
	}

	playback := natsPlayback{conn}
	bus := &natsBus{conn}
	liveRecording := &natsLiveRecording{conn}
	storedRecording := &natsStoredRecording{conn}
	logging := &natsLogging{conn}
	modules := &natsModules{conn}

	cl = &ari.Client{
		Cleanup:     func() error { nc.Close(); return nil },
		Asterisk:    &natsAsterisk{conn, logging, modules},
		Application: &natsApplication{conn},
		Bridge:      &natsBridge{conn, &playback, liveRecording},
		Channel:     &natsChannel{conn, &playback, liveRecording},
		DeviceState: &natsDeviceState{conn},
		Mailbox:     &natsMailbox{conn},
		Sound:       &natsSound{conn},
		Playback:    &playback,
		Recording: &ari.Recording{
			Live:   liveRecording,
			Stored: storedRecording,
		},
		Bus: bus,
	}

	return
}
<|endoftext|>


<commit_before>package blackbox

import (
	"log"
	"os"
	"time"

	"github.com/concourse/blackbox/datadog"
	"github.com/concourse/blackbox/expvar"
)

type Emitter struct {
	datadog datadog.Client
	expvar  expvar.Fetcher
}

func (e *Emitter) Run(signals <-chan os.Signal, ready chan<- struct{}) error {
	close(ready)

	for {
		expvars, err := e.expvar.Fetch()
		if err != nil {
			log.Println("failed to fetch expvars: %s", err)
			continue
		}

		series := make(datadog.Series, 0, expvars.Size())
		now := time.Now()

		expvars.Walk(func(path string, value float32) {
			series = append(series, datadog.Metric{
				Name: path,
				Points: []datadog.Point{
					{Timestamp: now, Value: value},
				},
				Host: "a-host",                 // TODO
				Tags: []string{"cool", "tags"}, // TODO
			})
		})

		if err := e.datadog.PublishSeries(series); err != nil {
			log.Println("failed publish series: %s", err)
		}

		time.Sleep(10 * time.Second) // TODO
	}

	return nil
}
<commit_msg>parameterize emitter<commit_after>package blackbox

import (
	"log"
	"os"
	"time"

	"github.com/concourse/blackbox/datadog"
	"github.com/concourse/blackbox/expvar"
)

type emitter struct {
	datadog datadog.Client
	expvar  expvar.Fetcher

	interval time.Duration
	host     string
	tags     []string
}

func NewEmitter(
	datadog datadog.Client,
	expvar expvar.Fetcher,
	interval time.Duration,
	host string,
	tags []string,
) *emitter {
	return &emitter{
		datadog:  datadog,
		expvar:   expvar,
		interval: interval,
		host:     host,
		tags:     tags,
	}
}

func (e *emitter) Run(signals <-chan os.Signal, ready chan<- struct{}) error {
	close(ready)

	for {
		expvars, err := e.expvar.Fetch()
		if err != nil {
			log.Println("failed to fetch expvars: %s", err)
			continue
		}

		series := make(datadog.Series, 0, expvars.Size())
		now := time.Now()

		expvars.Walk(func(path string, value float32) {
			series = append(series, datadog.Metric{
				Name: path,
				Points: []datadog.Point{
					{Timestamp: now, Value: value},
				},
				Host: e.host,
				Tags: e.tags,
			})
		})

		if err := e.datadog.PublishSeries(series); err != nil {
			log.Println("failed publish series: %s", err)
		}

		time.Sleep(e.interval)
	}

	return nil
}
<|endoftext|>


<commit_before>// +build linux,seccomp

package chroot

import (
	specs "github.com/opencontainers/runtime-spec/specs-go"
	"github.com/pkg/errors"
	libseccomp "github.com/seccomp/libseccomp-golang"
	"github.com/sirupsen/logrus"
)

// setSeccomp sets the seccomp filter for ourselves and any processes that we'll start.
func setSeccomp(spec *specs.Spec) error {
	logrus.Debugf("setting seccomp configuration")
	if spec.Linux.Seccomp == nil {
		return nil
	}
	mapAction := func(specAction specs.LinuxSeccompAction) libseccomp.ScmpAction {
		switch specAction {
		case specs.ActKill:
			return libseccomp.ActKill
		case specs.ActTrap:
			return libseccomp.ActTrap
		case specs.ActErrno:
			return libseccomp.ActErrno
		case specs.ActTrace:
			return libseccomp.ActTrace
		case specs.ActAllow:
			return libseccomp.ActAllow
		}
		return libseccomp.ActInvalid
	}
	mapArch := func(specArch specs.Arch) libseccomp.ScmpArch {
		switch specArch {
		case specs.ArchX86:
			return libseccomp.ArchX86
		case specs.ArchX86_64:
			return libseccomp.ArchAMD64
		case specs.ArchX32:
			return libseccomp.ArchX32
		case specs.ArchARM:
			return libseccomp.ArchARM
		case specs.ArchAARCH64:
			return libseccomp.ArchARM64
		case specs.ArchMIPS:
			return libseccomp.ArchMIPS
		case specs.ArchMIPS64:
			return libseccomp.ArchMIPS64
		case specs.ArchMIPS64N32:
			return libseccomp.ArchMIPS64N32
		case specs.ArchMIPSEL:
			return libseccomp.ArchMIPSEL
		case specs.ArchMIPSEL64:
			return libseccomp.ArchMIPSEL64
		case specs.ArchMIPSEL64N32:
			return libseccomp.ArchMIPSEL64N32
		case specs.ArchPPC:
			return libseccomp.ArchPPC
		case specs.ArchPPC64:
			return libseccomp.ArchPPC64
		case specs.ArchPPC64LE:
			return libseccomp.ArchPPC64LE
		case specs.ArchS390:
			return libseccomp.ArchS390
		case specs.ArchS390X:
			return libseccomp.ArchS390X
		case specs.ArchPARISC:
			/* fallthrough */ /* for now */
		case specs.ArchPARISC64:
			/* fallthrough */ /* for now */
		}
		return libseccomp.ArchInvalid
	}
	mapOp := func(op specs.LinuxSeccompOperator) libseccomp.ScmpCompareOp {
		switch op {
		case specs.OpNotEqual:
			return libseccomp.CompareNotEqual
		case specs.OpLessThan:
			return libseccomp.CompareLess
		case specs.OpLessEqual:
			return libseccomp.CompareLessOrEqual
		case specs.OpEqualTo:
			return libseccomp.CompareEqual
		case specs.OpGreaterEqual:
			return libseccomp.CompareGreaterEqual
		case specs.OpGreaterThan:
			return libseccomp.CompareGreater
		case specs.OpMaskedEqual:
			return libseccomp.CompareMaskedEqual
		}
		return libseccomp.CompareInvalid
	}

	filter, err := libseccomp.NewFilter(mapAction(spec.Linux.Seccomp.DefaultAction))
	if err != nil {
		return errors.Wrapf(err, "error creating seccomp filter with default action %q", spec.Linux.Seccomp.DefaultAction)
	}
	for _, arch := range spec.Linux.Seccomp.Architectures {
		if err = filter.AddArch(mapArch(arch)); err != nil {
			return errors.Wrapf(err, "error adding architecture %q(%q) to seccomp filter", arch, mapArch(arch))
		}
	}
	for _, rule := range spec.Linux.Seccomp.Syscalls {
		scnames := make(map[libseccomp.ScmpSyscall]string)
		for _, name := range rule.Names {
			scnum, err := libseccomp.GetSyscallFromName(name)
			if err != nil {
				logrus.Debugf("error mapping syscall %q to a syscall, ignoring %q rule for %q", name, rule.Action, name)
				continue
			}
			scnames[scnum] = name
		}
		for scnum := range scnames {
			if len(rule.Args) == 0 {
				if err = filter.AddRule(scnum, mapAction(rule.Action)); err != nil {
					return errors.Wrapf(err, "error adding a rule (%q:%q) to seccomp filter", scnames[scnum], rule.Action)
				}
				continue
			}
			var conditions []libseccomp.ScmpCondition
			opsAreAllEquality := true
			for _, arg := range rule.Args {
				condition, err := libseccomp.MakeCondition(arg.Index, mapOp(arg.Op), arg.Value, arg.ValueTwo)
				if err != nil {
					return errors.Wrapf(err, "error building a seccomp condition %d:%v:%d:%d", arg.Index, arg.Op, arg.Value, arg.ValueTwo)
				}
				if arg.Op != specs.OpEqualTo {
					opsAreAllEquality = false
				}
				conditions = append(conditions, condition)
			}
			if err = filter.AddRuleConditional(scnum, mapAction(rule.Action), conditions); err != nil {
				// Okay, if the rules specify multiple equality
				// checks, assume someone thought that they
				// were OR'd, when in fact they're ordinarily
				// supposed to be AND'd.  Break them up into
				// different rules to get that OR effect.
				if len(rule.Args) > 1 && opsAreAllEquality && err.Error() == "two checks on same syscall argument" {
					for i := range conditions {
						if err = filter.AddRuleConditional(scnum, mapAction(rule.Action), conditions[i:i+1]); err != nil {
							return errors.Wrapf(err, "error adding a conditional rule (%q:%q[%d]) to seccomp filter", scnames[scnum], rule.Action, i)
						}
					}
				} else {
					return errors.Wrapf(err, "error adding a conditional rule (%q:%q) to seccomp filter", scnames[scnum], rule.Action)
				}
			}
		}
	}
	if err = filter.SetNoNewPrivsBit(spec.Process.NoNewPrivileges); err != nil {
		return errors.Wrapf(err, "error setting no-new-privileges bit to %v", spec.Process.NoNewPrivileges)
	}
	err = filter.Load()
	filter.Release()
	if err != nil {
		return errors.Wrapf(err, "error activating seccomp filter")
	}
	return nil
}
<commit_msg>chroot: fix handling of errno seccomp rules<commit_after>// +build linux,seccomp

package chroot

import (
	specs "github.com/opencontainers/runtime-spec/specs-go"
	"github.com/pkg/errors"
	libseccomp "github.com/seccomp/libseccomp-golang"
	"github.com/sirupsen/logrus"
)

// setSeccomp sets the seccomp filter for ourselves and any processes that we'll start.
func setSeccomp(spec *specs.Spec) error {
	logrus.Debugf("setting seccomp configuration")
	if spec.Linux.Seccomp == nil {
		return nil
	}
	mapAction := func(specAction specs.LinuxSeccompAction, errnoRet *uint) libseccomp.ScmpAction {
		switch specAction {
		case specs.ActKill:
			return libseccomp.ActKill
		case specs.ActTrap:
			return libseccomp.ActTrap
		case specs.ActErrno:
			action := libseccomp.ActErrno
			if errnoRet != nil {
				action = action.SetReturnCode(int16(*errnoRet))
			}
			return action
		case specs.ActTrace:
			return libseccomp.ActTrace
		case specs.ActAllow:
			return libseccomp.ActAllow
		case specs.ActLog:
			return libseccomp.ActLog
		case specs.ActKillProcess:
			return libseccomp.ActKillProcess
		default:
			logrus.Errorf("unmappable action %v", specAction)
		}
		return libseccomp.ActInvalid
	}
	mapArch := func(specArch specs.Arch) libseccomp.ScmpArch {
		switch specArch {
		case specs.ArchX86:
			return libseccomp.ArchX86
		case specs.ArchX86_64:
			return libseccomp.ArchAMD64
		case specs.ArchX32:
			return libseccomp.ArchX32
		case specs.ArchARM:
			return libseccomp.ArchARM
		case specs.ArchAARCH64:
			return libseccomp.ArchARM64
		case specs.ArchMIPS:
			return libseccomp.ArchMIPS
		case specs.ArchMIPS64:
			return libseccomp.ArchMIPS64
		case specs.ArchMIPS64N32:
			return libseccomp.ArchMIPS64N32
		case specs.ArchMIPSEL:
			return libseccomp.ArchMIPSEL
		case specs.ArchMIPSEL64:
			return libseccomp.ArchMIPSEL64
		case specs.ArchMIPSEL64N32:
			return libseccomp.ArchMIPSEL64N32
		case specs.ArchPPC:
			return libseccomp.ArchPPC
		case specs.ArchPPC64:
			return libseccomp.ArchPPC64
		case specs.ArchPPC64LE:
			return libseccomp.ArchPPC64LE
		case specs.ArchS390:
			return libseccomp.ArchS390
		case specs.ArchS390X:
			return libseccomp.ArchS390X
		case specs.ArchPARISC:
			/* fallthrough */ /* for now */
		case specs.ArchPARISC64:
			/* fallthrough */ /* for now */
		default:
			logrus.Errorf("unmappable arch %v", specArch)
		}
		return libseccomp.ArchInvalid
	}
	mapOp := func(op specs.LinuxSeccompOperator) libseccomp.ScmpCompareOp {
		switch op {
		case specs.OpNotEqual:
			return libseccomp.CompareNotEqual
		case specs.OpLessThan:
			return libseccomp.CompareLess
		case specs.OpLessEqual:
			return libseccomp.CompareLessOrEqual
		case specs.OpEqualTo:
			return libseccomp.CompareEqual
		case specs.OpGreaterEqual:
			return libseccomp.CompareGreaterEqual
		case specs.OpGreaterThan:
			return libseccomp.CompareGreater
		case specs.OpMaskedEqual:
			return libseccomp.CompareMaskedEqual
		default:
			logrus.Errorf("unmappable op %v", op)
		}
		return libseccomp.CompareInvalid
	}

	filter, err := libseccomp.NewFilter(mapAction(spec.Linux.Seccomp.DefaultAction, nil))
	if err != nil {
		return errors.Wrapf(err, "error creating seccomp filter with default action %q", spec.Linux.Seccomp.DefaultAction)
	}
	for _, arch := range spec.Linux.Seccomp.Architectures {
		if err = filter.AddArch(mapArch(arch)); err != nil {
			return errors.Wrapf(err, "error adding architecture %q(%q) to seccomp filter", arch, mapArch(arch))
		}
	}
	for _, rule := range spec.Linux.Seccomp.Syscalls {
		scnames := make(map[libseccomp.ScmpSyscall]string)
		for _, name := range rule.Names {
			scnum, err := libseccomp.GetSyscallFromName(name)
			if err != nil {
				logrus.Debugf("error mapping syscall %q to a syscall, ignoring %q rule for %q", name, rule.Action, name)
				continue
			}
			scnames[scnum] = name
		}
		for scnum := range scnames {
			if len(rule.Args) == 0 {
				if err = filter.AddRule(scnum, mapAction(rule.Action, rule.ErrnoRet)); err != nil {
					return errors.Wrapf(err, "error adding a rule (%q:%q) to seccomp filter", scnames[scnum], rule.Action)
				}
				continue
			}
			var conditions []libseccomp.ScmpCondition
			opsAreAllEquality := true
			for _, arg := range rule.Args {
				condition, err := libseccomp.MakeCondition(arg.Index, mapOp(arg.Op), arg.Value, arg.ValueTwo)
				if err != nil {
					return errors.Wrapf(err, "error building a seccomp condition %d:%v:%d:%d", arg.Index, arg.Op, arg.Value, arg.ValueTwo)
				}
				if arg.Op != specs.OpEqualTo {
					opsAreAllEquality = false
				}
				conditions = append(conditions, condition)
			}
			if err = filter.AddRuleConditional(scnum, mapAction(rule.Action, rule.ErrnoRet), conditions); err != nil {
				// Okay, if the rules specify multiple equality
				// checks, assume someone thought that they
				// were OR'd, when in fact they're ordinarily
				// supposed to be AND'd.  Break them up into
				// different rules to get that OR effect.
				if len(rule.Args) > 1 && opsAreAllEquality && err.Error() == "two checks on same syscall argument" {
					for i := range conditions {
						if err = filter.AddRuleConditional(scnum, mapAction(rule.Action, rule.ErrnoRet), conditions[i:i+1]); err != nil {
							return errors.Wrapf(err, "error adding a conditional rule (%q:%q[%d]) to seccomp filter", scnames[scnum], rule.Action, i)
						}
					}
				} else {
					return errors.Wrapf(err, "error adding a conditional rule (%q:%q) to seccomp filter", scnames[scnum], rule.Action)
				}
			}
		}
	}
	if err = filter.SetNoNewPrivsBit(spec.Process.NoNewPrivileges); err != nil {
		return errors.Wrapf(err, "error setting no-new-privileges bit to %v", spec.Process.NoNewPrivileges)
	}
	err = filter.Load()
	filter.Release()
	if err != nil {
		return errors.Wrapf(err, "error activating seccomp filter")
	}
	return nil
}
<|endoftext|>


<commit_before>package radar_test

import (
	"errors"
	"os"
	"time"

	"github.com/concourse/atc"
	"github.com/concourse/atc/db"
	dbfakes "github.com/concourse/atc/db/fakes"
	"github.com/concourse/atc/worker"
	"github.com/pivotal-golang/lager/lagertest"
	"github.com/tedsuo/ifrit"

	. "github.com/concourse/atc/radar"
	"github.com/concourse/atc/radar/fakes"
	"github.com/concourse/atc/resource"
	rfakes "github.com/concourse/atc/resource/fakes"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Radar", func() {
	var (
		fakeTracker   *rfakes.FakeTracker
		fakeVersionDB *fakes.FakeVersionDB
		configDB      *dbfakes.FakeConfigDB
		interval      time.Duration

		radar *Radar

		resourceConfig atc.ResourceConfig

		locker               *fakes.FakeLocker
		readLock             *dbfakes.FakeLock
		writeLock            *dbfakes.FakeLock
		writeImmediatelyLock *dbfakes.FakeLock

		process ifrit.Process
	)

	BeforeEach(func() {
		fakeTracker = new(rfakes.FakeTracker)
		fakeVersionDB = new(fakes.FakeVersionDB)
		locker = new(fakes.FakeLocker)
		configDB = new(dbfakes.FakeConfigDB)
		interval = 100 * time.Millisecond

		radar = NewRadar(fakeTracker, fakeVersionDB, interval, locker, configDB)

		resourceConfig = atc.ResourceConfig{
			Name:   "some-resource",
			Type:   "git",
			Source: atc.Source{"uri": "http://example.com"},
		}

		configDB.GetConfigReturns(atc.Config{
			Resources: atc.ResourceConfigs{
				resourceConfig,
			},
		}, 1, nil)

		readLock = new(dbfakes.FakeLock)
		locker.AcquireReadLockReturns(readLock, nil)

		writeLock = new(dbfakes.FakeLock)
		locker.AcquireWriteLockReturns(writeLock, nil)

		writeImmediatelyLock = new(dbfakes.FakeLock)
		locker.AcquireWriteLockImmediatelyReturns(writeImmediatelyLock, nil)
	})

	Describe("Scanner", func() {
		var (
			fakeResource *rfakes.FakeResource

			times chan time.Time
		)

		BeforeEach(func() {
			fakeResource = new(rfakes.FakeResource)
			fakeTracker.InitReturns(fakeResource, nil)

			times = make(chan time.Time, 100)

			fakeResource.CheckStub = func(atc.Source, atc.Version) ([]atc.Version, error) {
				times <- time.Now()
				return nil, nil
			}
		})

		JustBeforeEach(func() {
			process = ifrit.Invoke(radar.Scanner(lagertest.NewTestLogger("test"), "some-resource"))
		})

		AfterEach(func() {
			process.Signal(os.Interrupt)
			Eventually(process.Wait()).Should(Receive())
		})

		It("constructs the resource of the correct type", func() {
			Eventually(times).Should(Receive())

			sessionID, typ := fakeTracker.InitArgsForCall(0)
			Ω(sessionID).Should(Equal(resource.Session{
				ID: worker.Identifier{
					Name: "some-resource",
					Type: "check",

					CheckType:   "git",
					CheckSource: resourceConfig.Source,
				},
				Ephemeral: true,
			}))
			Ω(typ).Should(Equal(resource.ResourceType("git")))
		})

		It("checks on a specified interval", func() {
			var time1 time.Time
			var time2 time.Time

			Eventually(times).Should(Receive(&time1))
			Eventually(times).Should(Receive(&time2))

			Ω(time2.Sub(time1)).Should(BeNumerically("~", interval, interval/4))
		})

		It("grabs a resource checking lock before checking, releases after done", func() {
			Eventually(times).Should(Receive())

			Ω(locker.AcquireWriteLockImmediatelyCallCount()).Should(Equal(1))

			lockedInputs := locker.AcquireWriteLockImmediatelyArgsForCall(0)
			Ω(lockedInputs).Should(Equal([]db.NamedLock{db.ResourceCheckingLock("some-resource")}))

			Ω(writeImmediatelyLock.ReleaseCallCount()).Should(Equal(1))
		})

		It("releases after checking", func() {
			Eventually(times).Should(Receive())

			Ω(fakeResource.ReleaseCallCount()).Should(Equal(1))
		})

		Context("when there is no current version", func() {
			It("checks from nil", func() {
				Eventually(times).Should(Receive())

				_, version := fakeResource.CheckArgsForCall(0)
				Ω(version).Should(BeNil())
			})
		})

		Context("when there is a current version", func() {
			BeforeEach(func() {
				fakeVersionDB.GetLatestVersionedResourceReturns(db.SavedVersionedResource{
					ID:                1,
					VersionedResource: db.VersionedResource{Version: db.Version{"version": "1"}},
				}, nil)
			})

			It("checks from it", func() {
				Eventually(times).Should(Receive())

				_, version := fakeResource.CheckArgsForCall(0)
				Ω(version).Should(Equal(atc.Version{"version": "1"}))

				fakeVersionDB.GetLatestVersionedResourceReturns(db.SavedVersionedResource{
					ID:                2,
					VersionedResource: db.VersionedResource{Version: db.Version{"version": "2"}},
				}, nil)

				Eventually(times).Should(Receive())

				_, version = fakeResource.CheckArgsForCall(1)
				Ω(version).Should(Equal(atc.Version{"version": "2"}))
			})
		})

		Context("when the check returns versions", func() {
			var checkedFrom chan atc.Version

			var nextVersions []atc.Version

			BeforeEach(func() {
				checkedFrom = make(chan atc.Version, 100)

				nextVersions = []atc.Version{
					{"version": "1"},
					{"version": "2"},
					{"version": "3"},
				}

				checkResults := map[int][]atc.Version{
					0: nextVersions,
				}

				check := 0
				fakeResource.CheckStub = func(source atc.Source, from atc.Version) ([]atc.Version, error) {
					defer GinkgoRecover()

					Ω(source).Should(Equal(resourceConfig.Source))

					checkedFrom <- from
					result := checkResults[check]
					check++

					return result, nil
				}
			})

			It("saves them all, in order", func() {
				Eventually(fakeVersionDB.SaveResourceVersionsCallCount).Should(Equal(1))

				resourceConfig, versions := fakeVersionDB.SaveResourceVersionsArgsForCall(0)
				Ω(resourceConfig).Should(Equal(atc.ResourceConfig{
					Name:   "some-resource",
					Type:   "git",
					Source: atc.Source{"uri": "http://example.com"},
				}))
				Ω(versions).Should(Equal([]atc.Version{
					{"version": "1"},
					{"version": "2"},
					{"version": "3"},
				}))
			})
		})

		Context("when checking fails", func() {
			disaster := errors.New("nope")

			BeforeEach(func() {
				fakeResource.CheckReturns(nil, disaster)
			})

			It("exits with the failure", func() {
				Eventually(process.Wait()).Should(Receive(Equal(disaster)))
			})
		})

		Context("when the config changes", func() {
			var newConfig atc.Config

			BeforeEach(func() {
				configs := make(chan atc.Config, 1)
				configs <- atc.Config{
					Resources: atc.ResourceConfigs{resourceConfig},
				}

				configDB.GetConfigStub = func() (atc.Config, db.ConfigID, error) {
					select {
					case c := <-configs:
						return c, 1, nil
					default:
						return newConfig, 2, nil
					}
				}
			})

			Context("with new configuration for the resource", func() {
				var newResource atc.ResourceConfig

				BeforeEach(func() {
					newResource = atc.ResourceConfig{
						Name:   "some-resource",
						Type:   "git",
						Source: atc.Source{"uri": "http://example.com/updated-uri"},
					}

					newConfig = atc.Config{
						Resources: atc.ResourceConfigs{newResource},
					}
				})

				It("checks using the new config", func() {
					Eventually(times).Should(Receive())

					source, _ := fakeResource.CheckArgsForCall(0)
					Ω(source).Should(Equal(resourceConfig.Source))

					Eventually(times).Should(Receive())

					source, _ = fakeResource.CheckArgsForCall(1)
					Ω(source).Should(Equal(atc.Source{"uri": "http://example.com/updated-uri"}))
				})
			})

			Context("with the resource removed", func() {
				BeforeEach(func() {
					newConfig = atc.Config{
						Resources: atc.ResourceConfigs{},
					}
				})

				It("exits", func() {
					Eventually(times).Should(Receive())

					source, _ := fakeResource.CheckArgsForCall(0)
					Ω(source).Should(Equal(resourceConfig.Source))

					Eventually(process.Wait()).Should(Receive())
				})
			})
		})

		Context("and checking takes a while", func() {
			BeforeEach(func() {
				checked := false

				fakeResource.CheckStub = func(atc.Source, atc.Version) ([]atc.Version, error) {
					times <- time.Now()

					if checked {
						time.Sleep(interval)
					}

					checked = true

					return nil, nil
				}
			})

			It("does not count it towards the interval", func() {
				var time1 time.Time
				var time2 time.Time

				Eventually(times).Should(Receive(&time1))
				Eventually(times, 2).Should(Receive(&time2))

				Ω(time2.Sub(time1)).Should(BeNumerically("~", interval, interval/2))
			})
		})
	})

	Describe("Scan", func() {
		var (
			fakeResource *rfakes.FakeResource

			scanErr error
		)

		BeforeEach(func() {
			fakeResource = new(rfakes.FakeResource)
			fakeTracker.InitReturns(fakeResource, nil)
		})

		JustBeforeEach(func() {
			scanErr = radar.Scan(lagertest.NewTestLogger("test"), "some-resource")
		})

		It("succeeds", func() {
			Ω(scanErr).ShouldNot(HaveOccurred())
		})

		It("constructs the resource of the correct type", func() {
			sessionID, typ := fakeTracker.InitArgsForCall(0)
			Ω(sessionID).Should(Equal(resource.Session{
				ID: worker.Identifier{
					Name: "some-resource",
					Type: "check",

					CheckType:   "git",
					CheckSource: resourceConfig.Source,
				},
				Ephemeral: true,
			}))
			Ω(typ).Should(Equal(resource.ResourceType("git")))
		})

		It("grabs a resource checking lock before checking, releases after done", func() {
			Ω(locker.AcquireWriteLockCallCount()).Should(Equal(1))

			lockedInputs := locker.AcquireWriteLockArgsForCall(0)
			Ω(lockedInputs).Should(Equal([]db.NamedLock{db.ResourceCheckingLock("some-resource")}))

			Ω(writeLock.ReleaseCallCount()).Should(Equal(1))
		})

		It("releases the resource", func() {
			Ω(fakeResource.ReleaseCallCount()).Should(Equal(1))
		})

		Context("when there is no current version", func() {
			It("checks from nil", func() {
				_, version := fakeResource.CheckArgsForCall(0)
				Ω(version).Should(BeNil())
			})
		})

		Context("when there is a current version", func() {
			BeforeEach(func() {
				fakeVersionDB.GetLatestVersionedResourceReturns(db.SavedVersionedResource{
					ID:                1,
					VersionedResource: db.VersionedResource{Version: db.Version{"version": "1"}},
				}, nil)
			})

			It("checks from it", func() {
				_, version := fakeResource.CheckArgsForCall(0)
				Ω(version).Should(Equal(atc.Version{"version": "1"}))
			})
		})

		Context("when the check returns versions", func() {
			var checkedFrom chan atc.Version

			var nextVersions []atc.Version

			BeforeEach(func() {
				checkedFrom = make(chan atc.Version, 100)

				nextVersions = []atc.Version{
					{"version": "1"},
					{"version": "2"},
					{"version": "3"},
				}

				checkResults := map[int][]atc.Version{
					0: nextVersions,
				}

				check := 0
				fakeResource.CheckStub = func(source atc.Source, from atc.Version) ([]atc.Version, error) {
					defer GinkgoRecover()

					Ω(source).Should(Equal(resourceConfig.Source))

					checkedFrom <- from
					result := checkResults[check]
					check++

					return result, nil
				}
			})

			It("saves them all, in order", func() {
				Ω(fakeVersionDB.SaveResourceVersionsCallCount()).Should(Equal(1))

				resourceConfig, versions := fakeVersionDB.SaveResourceVersionsArgsForCall(0)
				Ω(resourceConfig).Should(Equal(atc.ResourceConfig{
					Name:   "some-resource",
					Type:   "git",
					Source: atc.Source{"uri": "http://example.com"},
				}))
				Ω(versions).Should(Equal([]atc.Version{
					{"version": "1"},
					{"version": "2"},
					{"version": "3"},
				}))
			})
		})

		Context("when checking fails", func() {
			disaster := errors.New("nope")

			BeforeEach(func() {
				fakeResource.CheckReturns(nil, disaster)
			})

			It("returns the error", func() {
				Ω(scanErr).Should(Equal(disaster))
			})
		})
	})
})
<commit_msg>fix flaky assertion<commit_after>package radar_test

import (
	"errors"
	"os"
	"time"

	"github.com/concourse/atc"
	"github.com/concourse/atc/db"
	dbfakes "github.com/concourse/atc/db/fakes"
	"github.com/concourse/atc/worker"
	"github.com/pivotal-golang/lager/lagertest"
	"github.com/tedsuo/ifrit"

	. "github.com/concourse/atc/radar"
	"github.com/concourse/atc/radar/fakes"
	"github.com/concourse/atc/resource"
	rfakes "github.com/concourse/atc/resource/fakes"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Radar", func() {
	var (
		fakeTracker   *rfakes.FakeTracker
		fakeVersionDB *fakes.FakeVersionDB
		configDB      *dbfakes.FakeConfigDB
		interval      time.Duration

		radar *Radar

		resourceConfig atc.ResourceConfig

		locker               *fakes.FakeLocker
		readLock             *dbfakes.FakeLock
		writeLock            *dbfakes.FakeLock
		writeImmediatelyLock *dbfakes.FakeLock

		process ifrit.Process
	)

	BeforeEach(func() {
		fakeTracker = new(rfakes.FakeTracker)
		fakeVersionDB = new(fakes.FakeVersionDB)
		locker = new(fakes.FakeLocker)
		configDB = new(dbfakes.FakeConfigDB)
		interval = 100 * time.Millisecond

		radar = NewRadar(fakeTracker, fakeVersionDB, interval, locker, configDB)

		resourceConfig = atc.ResourceConfig{
			Name:   "some-resource",
			Type:   "git",
			Source: atc.Source{"uri": "http://example.com"},
		}

		configDB.GetConfigReturns(atc.Config{
			Resources: atc.ResourceConfigs{
				resourceConfig,
			},
		}, 1, nil)

		readLock = new(dbfakes.FakeLock)
		locker.AcquireReadLockReturns(readLock, nil)

		writeLock = new(dbfakes.FakeLock)
		locker.AcquireWriteLockReturns(writeLock, nil)

		writeImmediatelyLock = new(dbfakes.FakeLock)
		locker.AcquireWriteLockImmediatelyReturns(writeImmediatelyLock, nil)
	})

	Describe("Scanner", func() {
		var (
			fakeResource *rfakes.FakeResource

			times chan time.Time
		)

		BeforeEach(func() {
			fakeResource = new(rfakes.FakeResource)
			fakeTracker.InitReturns(fakeResource, nil)

			times = make(chan time.Time, 100)

			fakeResource.CheckStub = func(atc.Source, atc.Version) ([]atc.Version, error) {
				times <- time.Now()
				return nil, nil
			}
		})

		JustBeforeEach(func() {
			process = ifrit.Invoke(radar.Scanner(lagertest.NewTestLogger("test"), "some-resource"))
		})

		AfterEach(func() {
			process.Signal(os.Interrupt)
			<-process.Wait()
		})

		It("constructs the resource of the correct type", func() {
			Eventually(times).Should(Receive())

			sessionID, typ := fakeTracker.InitArgsForCall(0)
			Ω(sessionID).Should(Equal(resource.Session{
				ID: worker.Identifier{
					Name: "some-resource",
					Type: "check",

					CheckType:   "git",
					CheckSource: resourceConfig.Source,
				},
				Ephemeral: true,
			}))
			Ω(typ).Should(Equal(resource.ResourceType("git")))
		})

		It("checks on a specified interval", func() {
			var time1 time.Time
			var time2 time.Time

			Eventually(times).Should(Receive(&time1))
			Eventually(times).Should(Receive(&time2))

			Ω(time2.Sub(time1)).Should(BeNumerically("~", interval, interval/4))
		})

		It("grabs a resource checking lock before checking, releases after done", func() {
			Eventually(times).Should(Receive())

			Ω(locker.AcquireWriteLockImmediatelyCallCount()).Should(Equal(1))

			lockedInputs := locker.AcquireWriteLockImmediatelyArgsForCall(0)
			Ω(lockedInputs).Should(Equal([]db.NamedLock{db.ResourceCheckingLock("some-resource")}))

			Ω(writeImmediatelyLock.ReleaseCallCount()).Should(Equal(1))
		})

		It("releases after checking", func() {
			Eventually(times).Should(Receive())

			Ω(fakeResource.ReleaseCallCount()).Should(Equal(1))
		})

		Context("when there is no current version", func() {
			It("checks from nil", func() {
				Eventually(times).Should(Receive())

				_, version := fakeResource.CheckArgsForCall(0)
				Ω(version).Should(BeNil())
			})
		})

		Context("when there is a current version", func() {
			BeforeEach(func() {
				fakeVersionDB.GetLatestVersionedResourceReturns(db.SavedVersionedResource{
					ID:                1,
					VersionedResource: db.VersionedResource{Version: db.Version{"version": "1"}},
				}, nil)
			})

			It("checks from it", func() {
				Eventually(times).Should(Receive())

				_, version := fakeResource.CheckArgsForCall(0)
				Ω(version).Should(Equal(atc.Version{"version": "1"}))

				fakeVersionDB.GetLatestVersionedResourceReturns(db.SavedVersionedResource{
					ID:                2,
					VersionedResource: db.VersionedResource{Version: db.Version{"version": "2"}},
				}, nil)

				Eventually(times).Should(Receive())

				_, version = fakeResource.CheckArgsForCall(1)
				Ω(version).Should(Equal(atc.Version{"version": "2"}))
			})
		})

		Context("when the check returns versions", func() {
			var checkedFrom chan atc.Version

			var nextVersions []atc.Version

			BeforeEach(func() {
				checkedFrom = make(chan atc.Version, 100)

				nextVersions = []atc.Version{
					{"version": "1"},
					{"version": "2"},
					{"version": "3"},
				}

				checkResults := map[int][]atc.Version{
					0: nextVersions,
				}

				check := 0
				fakeResource.CheckStub = func(source atc.Source, from atc.Version) ([]atc.Version, error) {
					defer GinkgoRecover()

					Ω(source).Should(Equal(resourceConfig.Source))

					checkedFrom <- from
					result := checkResults[check]
					check++

					return result, nil
				}
			})

			It("saves them all, in order", func() {
				Eventually(fakeVersionDB.SaveResourceVersionsCallCount).Should(Equal(1))

				resourceConfig, versions := fakeVersionDB.SaveResourceVersionsArgsForCall(0)
				Ω(resourceConfig).Should(Equal(atc.ResourceConfig{
					Name:   "some-resource",
					Type:   "git",
					Source: atc.Source{"uri": "http://example.com"},
				}))
				Ω(versions).Should(Equal([]atc.Version{
					{"version": "1"},
					{"version": "2"},
					{"version": "3"},
				}))
			})
		})

		Context("when checking fails", func() {
			disaster := errors.New("nope")

			BeforeEach(func() {
				fakeResource.CheckReturns(nil, disaster)
			})

			It("exits with the failure", func() {
				Eventually(process.Wait()).Should(Receive(Equal(disaster)))
			})
		})

		Context("when the config changes", func() {
			var newConfig atc.Config

			BeforeEach(func() {
				configs := make(chan atc.Config, 1)
				configs <- atc.Config{
					Resources: atc.ResourceConfigs{resourceConfig},
				}

				configDB.GetConfigStub = func() (atc.Config, db.ConfigID, error) {
					select {
					case c := <-configs:
						return c, 1, nil
					default:
						return newConfig, 2, nil
					}
				}
			})

			Context("with new configuration for the resource", func() {
				var newResource atc.ResourceConfig

				BeforeEach(func() {
					newResource = atc.ResourceConfig{
						Name:   "some-resource",
						Type:   "git",
						Source: atc.Source{"uri": "http://example.com/updated-uri"},
					}

					newConfig = atc.Config{
						Resources: atc.ResourceConfigs{newResource},
					}
				})

				It("checks using the new config", func() {
					Eventually(times).Should(Receive())

					source, _ := fakeResource.CheckArgsForCall(0)
					Ω(source).Should(Equal(resourceConfig.Source))

					Eventually(times).Should(Receive())

					source, _ = fakeResource.CheckArgsForCall(1)
					Ω(source).Should(Equal(atc.Source{"uri": "http://example.com/updated-uri"}))
				})
			})

			Context("with the resource removed", func() {
				BeforeEach(func() {
					newConfig = atc.Config{
						Resources: atc.ResourceConfigs{},
					}
				})

				It("exits", func() {
					Eventually(times).Should(Receive())

					source, _ := fakeResource.CheckArgsForCall(0)
					Ω(source).Should(Equal(resourceConfig.Source))

					Eventually(process.Wait()).Should(Receive())
				})
			})
		})

		Context("and checking takes a while", func() {
			BeforeEach(func() {
				checked := false

				fakeResource.CheckStub = func(atc.Source, atc.Version) ([]atc.Version, error) {
					times <- time.Now()

					if checked {
						time.Sleep(interval)
					}

					checked = true

					return nil, nil
				}
			})

			It("does not count it towards the interval", func() {
				var time1 time.Time
				var time2 time.Time

				Eventually(times).Should(Receive(&time1))
				Eventually(times, 2).Should(Receive(&time2))

				Ω(time2.Sub(time1)).Should(BeNumerically("~", interval, interval/2))
			})
		})
	})

	Describe("Scan", func() {
		var (
			fakeResource *rfakes.FakeResource

			scanErr error
		)

		BeforeEach(func() {
			fakeResource = new(rfakes.FakeResource)
			fakeTracker.InitReturns(fakeResource, nil)
		})

		JustBeforeEach(func() {
			scanErr = radar.Scan(lagertest.NewTestLogger("test"), "some-resource")
		})

		It("succeeds", func() {
			Ω(scanErr).ShouldNot(HaveOccurred())
		})

		It("constructs the resource of the correct type", func() {
			sessionID, typ := fakeTracker.InitArgsForCall(0)
			Ω(sessionID).Should(Equal(resource.Session{
				ID: worker.Identifier{
					Name: "some-resource",
					Type: "check",

					CheckType:   "git",
					CheckSource: resourceConfig.Source,
				},
				Ephemeral: true,
			}))
			Ω(typ).Should(Equal(resource.ResourceType("git")))
		})

		It("grabs a resource checking lock before checking, releases after done", func() {
			Ω(locker.AcquireWriteLockCallCount()).Should(Equal(1))

			lockedInputs := locker.AcquireWriteLockArgsForCall(0)
			Ω(lockedInputs).Should(Equal([]db.NamedLock{db.ResourceCheckingLock("some-resource")}))

			Ω(writeLock.ReleaseCallCount()).Should(Equal(1))
		})

		It("releases the resource", func() {
			Ω(fakeResource.ReleaseCallCount()).Should(Equal(1))
		})

		Context("when there is no current version", func() {
			It("checks from nil", func() {
				_, version := fakeResource.CheckArgsForCall(0)
				Ω(version).Should(BeNil())
			})
		})

		Context("when there is a current version", func() {
			BeforeEach(func() {
				fakeVersionDB.GetLatestVersionedResourceReturns(db.SavedVersionedResource{
					ID:                1,
					VersionedResource: db.VersionedResource{Version: db.Version{"version": "1"}},
				}, nil)
			})

			It("checks from it", func() {
				_, version := fakeResource.CheckArgsForCall(0)
				Ω(version).Should(Equal(atc.Version{"version": "1"}))
			})
		})

		Context("when the check returns versions", func() {
			var checkedFrom chan atc.Version

			var nextVersions []atc.Version

			BeforeEach(func() {
				checkedFrom = make(chan atc.Version, 100)

				nextVersions = []atc.Version{
					{"version": "1"},
					{"version": "2"},
					{"version": "3"},
				}

				checkResults := map[int][]atc.Version{
					0: nextVersions,
				}

				check := 0
				fakeResource.CheckStub = func(source atc.Source, from atc.Version) ([]atc.Version, error) {
					defer GinkgoRecover()

					Ω(source).Should(Equal(resourceConfig.Source))

					checkedFrom <- from
					result := checkResults[check]
					check++

					return result, nil
				}
			})

			It("saves them all, in order", func() {
				Ω(fakeVersionDB.SaveResourceVersionsCallCount()).Should(Equal(1))

				resourceConfig, versions := fakeVersionDB.SaveResourceVersionsArgsForCall(0)
				Ω(resourceConfig).Should(Equal(atc.ResourceConfig{
					Name:   "some-resource",
					Type:   "git",
					Source: atc.Source{"uri": "http://example.com"},
				}))
				Ω(versions).Should(Equal([]atc.Version{
					{"version": "1"},
					{"version": "2"},
					{"version": "3"},
				}))
			})
		})

		Context("when checking fails", func() {
			disaster := errors.New("nope")

			BeforeEach(func() {
				fakeResource.CheckReturns(nil, disaster)
			})

			It("returns the error", func() {
				Ω(scanErr).Should(Equal(disaster))
			})
		})
	})
})
<|endoftext|>


<commit_before>package graph

import (
	"errors"
	"fmt"
	"log"
	"math"
	"time"

	cmodel "github.com/Cepave/common/model"
	cutils "github.com/Cepave/common/utils"
	rings "github.com/toolkits/consistent/rings"
	nset "github.com/toolkits/container/set"
	spool "github.com/toolkits/pool/simple_conn_pool"

	"github.com/Cepave/query/g"
)

// 连接池
// node_address -> connection_pool
var (
	GraphConnPools *spool.SafeRpcConnPools
)

// 服务节点的一致性哈希环
// pk -> node
var (
	GraphNodeRing *rings.ConsistentHashNodeRing
)

func Start() {
	initNodeRings()
	initConnPools()
	log.Println("graph.Start ok")
}

func QueryOne(para cmodel.GraphQueryParam) (resp *cmodel.GraphQueryResponse, err error) {
	start, end := para.Start, para.End
	endpoint, counter := para.Endpoint, para.Counter

	pool, addr, err := selectPool(endpoint, counter)
	if err != nil {
		return nil, err
	}

	conn, err := pool.Fetch()
	if err != nil {
		return nil, err
	}

	rpcConn := conn.(spool.RpcClient)
	if rpcConn.Closed() {
		pool.ForceClose(conn)
		return nil, errors.New("conn closed")
	}

	type ChResult struct {
		Err  error
		Resp *cmodel.GraphQueryResponse
	}

	ch := make(chan *ChResult, 1)
	go func() {
		resp := &cmodel.GraphQueryResponse{}
		err := rpcConn.Call("Graph.Query", para, resp)
		ch <- &ChResult{Err: err, Resp: resp}
	}()

	select {
	case <-time.After(time.Duration(g.Config().Graph.CallTimeout) * time.Millisecond):
		pool.ForceClose(conn)
		return nil, fmt.Errorf("%s, call timeout. proc: %s", addr, pool.Proc())
	case r := <-ch:
		if r.Err != nil {
			pool.ForceClose(conn)
			return r.Resp, fmt.Errorf("%s, call failed, err %v. proc: %s", addr, r.Err, pool.Proc())
		} else {
			pool.Release(conn)

			if len(r.Resp.Values) < 1 {
				return r.Resp, nil
			}

			// TODO query不该做这些事情, 说明graph没做好
			fixed := []*cmodel.RRDData{}
			for _, v := range r.Resp.Values {
				if v == nil || !(v.Timestamp >= start && v.Timestamp <= end) {
					continue
				}
				//FIXME: 查询数据的时候，把所有的负值都过滤掉，因为transfer之前在设置最小值的时候为U
				if (r.Resp.DsType == "DERIVE" || r.Resp.DsType == "COUNTER") && v.Value < 0 {
					fixed = append(fixed, &cmodel.RRDData{Timestamp: v.Timestamp, Value: cmodel.JsonFloat(math.NaN())})
				} else {
					fixed = append(fixed, v)
				}
			}
			r.Resp.Values = fixed
		}
		return r.Resp, nil
	}
}

func Info(para cmodel.GraphInfoParam) (resp *cmodel.GraphFullyInfo, err error) {
	endpoint, counter := para.Endpoint, para.Counter

	pool, addr, err := selectPool(endpoint, counter)
	if err != nil {
		return nil, err
	}

	conn, err := pool.Fetch()
	if err != nil {
		return nil, err
	}

	rpcConn := conn.(spool.RpcClient)
	if rpcConn.Closed() {
		pool.ForceClose(conn)
		return nil, errors.New("conn closed")
	}

	type ChResult struct {
		Err  error
		Resp *cmodel.GraphInfoResp
	}
	ch := make(chan *ChResult, 1)
	go func() {
		resp := &cmodel.GraphInfoResp{}
		err := rpcConn.Call("Graph.Info", para, resp)
		ch <- &ChResult{Err: err, Resp: resp}
	}()

	select {
	case <-time.After(time.Duration(g.Config().Graph.CallTimeout) * time.Millisecond):
		pool.ForceClose(conn)
		return nil, fmt.Errorf("%s, call timeout. proc: %s", addr, pool.Proc())
	case r := <-ch:
		if r.Err != nil {
			pool.ForceClose(conn)
			return nil, fmt.Errorf("%s, call failed, err %v. proc: %s", addr, r.Err, pool.Proc())
		} else {
			pool.Release(conn)
			fullyInfo := cmodel.GraphFullyInfo{
				Endpoint:  endpoint,
				Counter:   counter,
				ConsolFun: r.Resp.ConsolFun,
				Step:      r.Resp.Step,
				Filename:  r.Resp.Filename,
				Addr:      addr,
			}
			return &fullyInfo, nil
		}
	}
}

func Last(para cmodel.GraphLastParam) (r *cmodel.GraphLastResp, err error) {
	endpoint, counter := para.Endpoint, para.Counter

	pool, addr, err := selectPool(endpoint, counter)
	if err != nil {
		return nil, err
	}

	conn, err := pool.Fetch()
	if err != nil {
		return nil, err
	}

	rpcConn := conn.(spool.RpcClient)
	if rpcConn.Closed() {
		pool.ForceClose(conn)
		return nil, errors.New("conn closed")
	}

	type ChResult struct {
		Err  error
		Resp *cmodel.GraphLastResp
	}
	ch := make(chan *ChResult, 1)
	go func() {
		resp := &cmodel.GraphLastResp{}
		err := rpcConn.Call("Graph.Last", para, resp)
		ch <- &ChResult{Err: err, Resp: resp}
	}()

	select {
	case <-time.After(time.Duration(g.Config().Graph.CallTimeout) * time.Millisecond):
		pool.ForceClose(conn)
		return nil, fmt.Errorf("%s, call timeout. proc: %s", addr, pool.Proc())
	case r := <-ch:
		if r.Err != nil {
			pool.ForceClose(conn)
			return r.Resp, fmt.Errorf("%s, call failed, err %v. proc: %s", addr, r.Err, pool.Proc())
		} else {
			pool.Release(conn)
			return r.Resp, nil
		}
	}
}

func LastRaw(para cmodel.GraphLastParam) (r *cmodel.GraphLastResp, err error) {
	endpoint, counter := para.Endpoint, para.Counter

	pool, addr, err := selectPool(endpoint, counter)
	if err != nil {
		return nil, err
	}

	conn, err := pool.Fetch()
	if err != nil {
		return nil, err
	}

	rpcConn := conn.(spool.RpcClient)
	if rpcConn.Closed() {
		pool.ForceClose(conn)
		return nil, errors.New("conn closed")
	}

	type ChResult struct {
		Err  error
		Resp *cmodel.GraphLastResp
	}
	ch := make(chan *ChResult, 1)
	go func() {
		resp := &cmodel.GraphLastResp{}
		err := rpcConn.Call("Graph.LastRaw", para, resp)
		ch <- &ChResult{Err: err, Resp: resp}
	}()

	select {
	case <-time.After(time.Duration(g.Config().Graph.CallTimeout) * time.Millisecond):
		pool.ForceClose(conn)
		return nil, fmt.Errorf("%s, call timeout. proc: %s", addr, pool.Proc())
	case r := <-ch:
		if r.Err != nil {
			pool.ForceClose(conn)
			return r.Resp, fmt.Errorf("%s, call failed, err %v. proc: %s", addr, r.Err, pool.Proc())
		} else {
			pool.Release(conn)
			return r.Resp, nil
		}
	}
}

func selectPool(endpoint, counter string) (rpool *spool.ConnPool, raddr string, rerr error) {
	pkey := cutils.PK2(endpoint, counter)
	node, err := GraphNodeRing.GetNode(pkey)
	if err != nil {
		return nil, "", err
	}

	addr, found := g.Config().Graph.Cluster[node]
	if !found {
		return nil, "", errors.New("node not found")
	}

	pool, found := GraphConnPools.Get(addr)
	if !found {
		return nil, addr, errors.New("addr not found")
	}

	return pool, addr, nil
}

// internal functions
func initConnPools() {
	cfg := g.Config()

	// TODO 为了得到Slice,这里做的太复杂了
	graphInstances := nset.NewSafeSet()
	for _, address := range cfg.Graph.Cluster {
		graphInstances.Add(address)
	}
	GraphConnPools = spool.CreateSafeRpcConnPools(cfg.Graph.MaxConns, cfg.Graph.MaxIdle,
		cfg.Graph.ConnTimeout, cfg.Graph.CallTimeout, graphInstances.ToSlice())
}

func initNodeRings() {
	cfg := g.Config()
	GraphNodeRing = rings.NewConsistentHashNodesRing(cfg.Graph.Replicas, cutils.KeysOfMap(cfg.Graph.Cluster))
}
<commit_msg>fixed null Values return problem<commit_after>package graph

import (
	"errors"
	"fmt"
	"log"
	"math"
	"time"

	cmodel "github.com/Cepave/common/model"
	cutils "github.com/Cepave/common/utils"
	rings "github.com/toolkits/consistent/rings"
	nset "github.com/toolkits/container/set"
	spool "github.com/toolkits/pool/simple_conn_pool"

	"github.com/Cepave/query/g"
)

// 连接池
// node_address -> connection_pool
var (
	GraphConnPools *spool.SafeRpcConnPools
)

// 服务节点的一致性哈希环
// pk -> node
var (
	GraphNodeRing *rings.ConsistentHashNodeRing
)

func Start() {
	initNodeRings()
	initConnPools()
	log.Println("graph.Start ok")
}

func QueryOne(para cmodel.GraphQueryParam) (resp *cmodel.GraphQueryResponse, err error) {
	start, end := para.Start, para.End
	endpoint, counter := para.Endpoint, para.Counter

	pool, addr, err := selectPool(endpoint, counter)
	if err != nil {
		return nil, err
	}

	conn, err := pool.Fetch()
	if err != nil {
		return nil, err
	}

	rpcConn := conn.(spool.RpcClient)
	if rpcConn.Closed() {
		pool.ForceClose(conn)
		return nil, errors.New("conn closed")
	}

	type ChResult struct {
		Err  error
		Resp *cmodel.GraphQueryResponse
	}

	ch := make(chan *ChResult, 1)
	go func() {
		resp := &cmodel.GraphQueryResponse{}
		err := rpcConn.Call("Graph.Query", para, resp)
		ch <- &ChResult{Err: err, Resp: resp}
	}()

	select {
	case <-time.After(time.Duration(g.Config().Graph.CallTimeout) * time.Millisecond):
		pool.ForceClose(conn)
		return nil, fmt.Errorf("%s, call timeout. proc: %s", addr, pool.Proc())
	case r := <-ch:
		if r.Err != nil {
			pool.ForceClose(conn)
			return r.Resp, fmt.Errorf("%s, call failed, err %v. proc: %s", addr, r.Err, pool.Proc())
		} else {
			pool.Release(conn)

			if len(r.Resp.Values) < 1 {
				r.Resp.Values = []*cmodel.RRDData{}
				return r.Resp, nil
			}

			// TODO query不该做这些事情, 说明graph没做好
			fixed := []*cmodel.RRDData{}
			for _, v := range r.Resp.Values {
				if v == nil || !(v.Timestamp >= start && v.Timestamp <= end) {
					continue
				}
				//FIXME: 查询数据的时候，把所有的负值都过滤掉，因为transfer之前在设置最小值的时候为U
				if (r.Resp.DsType == "DERIVE" || r.Resp.DsType == "COUNTER") && v.Value < 0 {
					fixed = append(fixed, &cmodel.RRDData{Timestamp: v.Timestamp, Value: cmodel.JsonFloat(math.NaN())})
				} else {
					fixed = append(fixed, v)
				}
			}
			r.Resp.Values = fixed
		}
		return r.Resp, nil
	}
}

func Info(para cmodel.GraphInfoParam) (resp *cmodel.GraphFullyInfo, err error) {
	endpoint, counter := para.Endpoint, para.Counter

	pool, addr, err := selectPool(endpoint, counter)
	if err != nil {
		return nil, err
	}

	conn, err := pool.Fetch()
	if err != nil {
		return nil, err
	}

	rpcConn := conn.(spool.RpcClient)
	if rpcConn.Closed() {
		pool.ForceClose(conn)
		return nil, errors.New("conn closed")
	}

	type ChResult struct {
		Err  error
		Resp *cmodel.GraphInfoResp
	}
	ch := make(chan *ChResult, 1)
	go func() {
		resp := &cmodel.GraphInfoResp{}
		err := rpcConn.Call("Graph.Info", para, resp)
		ch <- &ChResult{Err: err, Resp: resp}
	}()

	select {
	case <-time.After(time.Duration(g.Config().Graph.CallTimeout) * time.Millisecond):
		pool.ForceClose(conn)
		return nil, fmt.Errorf("%s, call timeout. proc: %s", addr, pool.Proc())
	case r := <-ch:
		if r.Err != nil {
			pool.ForceClose(conn)
			return nil, fmt.Errorf("%s, call failed, err %v. proc: %s", addr, r.Err, pool.Proc())
		} else {
			pool.Release(conn)
			fullyInfo := cmodel.GraphFullyInfo{
				Endpoint:  endpoint,
				Counter:   counter,
				ConsolFun: r.Resp.ConsolFun,
				Step:      r.Resp.Step,
				Filename:  r.Resp.Filename,
				Addr:      addr,
			}
			return &fullyInfo, nil
		}
	}
}

func Last(para cmodel.GraphLastParam) (r *cmodel.GraphLastResp, err error) {
	endpoint, counter := para.Endpoint, para.Counter

	pool, addr, err := selectPool(endpoint, counter)
	if err != nil {
		return nil, err
	}

	conn, err := pool.Fetch()
	if err != nil {
		return nil, err
	}

	rpcConn := conn.(spool.RpcClient)
	if rpcConn.Closed() {
		pool.ForceClose(conn)
		return nil, errors.New("conn closed")
	}

	type ChResult struct {
		Err  error
		Resp *cmodel.GraphLastResp
	}
	ch := make(chan *ChResult, 1)
	go func() {
		resp := &cmodel.GraphLastResp{}
		err := rpcConn.Call("Graph.Last", para, resp)
		ch <- &ChResult{Err: err, Resp: resp}
	}()

	select {
	case <-time.After(time.Duration(g.Config().Graph.CallTimeout) * time.Millisecond):
		pool.ForceClose(conn)
		return nil, fmt.Errorf("%s, call timeout. proc: %s", addr, pool.Proc())
	case r := <-ch:
		if r.Err != nil {
			pool.ForceClose(conn)
			return r.Resp, fmt.Errorf("%s, call failed, err %v. proc: %s", addr, r.Err, pool.Proc())
		} else {
			pool.Release(conn)
			return r.Resp, nil
		}
	}
}

func LastRaw(para cmodel.GraphLastParam) (r *cmodel.GraphLastResp, err error) {
	endpoint, counter := para.Endpoint, para.Counter

	pool, addr, err := selectPool(endpoint, counter)
	if err != nil {
		return nil, err
	}

	conn, err := pool.Fetch()
	if err != nil {
		return nil, err
	}

	rpcConn := conn.(spool.RpcClient)
	if rpcConn.Closed() {
		pool.ForceClose(conn)
		return nil, errors.New("conn closed")
	}

	type ChResult struct {
		Err  error
		Resp *cmodel.GraphLastResp
	}
	ch := make(chan *ChResult, 1)
	go func() {
		resp := &cmodel.GraphLastResp{}
		err := rpcConn.Call("Graph.LastRaw", para, resp)
		ch <- &ChResult{Err: err, Resp: resp}
	}()

	select {
	case <-time.After(time.Duration(g.Config().Graph.CallTimeout) * time.Millisecond):
		pool.ForceClose(conn)
		return nil, fmt.Errorf("%s, call timeout. proc: %s", addr, pool.Proc())
	case r := <-ch:
		if r.Err != nil {
			pool.ForceClose(conn)
			return r.Resp, fmt.Errorf("%s, call failed, err %v. proc: %s", addr, r.Err, pool.Proc())
		} else {
			pool.Release(conn)
			return r.Resp, nil
		}
	}
}

func selectPool(endpoint, counter string) (rpool *spool.ConnPool, raddr string, rerr error) {
	pkey := cutils.PK2(endpoint, counter)
	node, err := GraphNodeRing.GetNode(pkey)
	if err != nil {
		return nil, "", err
	}

	addr, found := g.Config().Graph.Cluster[node]
	if !found {
		return nil, "", errors.New("node not found")
	}

	pool, found := GraphConnPools.Get(addr)
	if !found {
		return nil, addr, errors.New("addr not found")
	}

	return pool, addr, nil
}

// internal functions
func initConnPools() {
	cfg := g.Config()

	// TODO 为了得到Slice,这里做的太复杂了
	graphInstances := nset.NewSafeSet()
	for _, address := range cfg.Graph.Cluster {
		graphInstances.Add(address)
	}
	GraphConnPools = spool.CreateSafeRpcConnPools(cfg.Graph.MaxConns, cfg.Graph.MaxIdle,
		cfg.Graph.ConnTimeout, cfg.Graph.CallTimeout, graphInstances.ToSlice())
}

func initNodeRings() {
	cfg := g.Config()
	GraphNodeRing = rings.NewConsistentHashNodesRing(cfg.Graph.Replicas, cutils.KeysOfMap(cfg.Graph.Cluster))
}
<|endoftext|>