<commit_before>package main

import (
	"bufio"
	"io/ioutil"
	"os"
	"runtime"
	"sort"
	"strconv"
	"strings"
)

// ProcessMonitor keeps tracks of the processes running on the system.
type ProcessMonitor struct {
	List []*Process
	Map  map[int]*Process

	NumCPUs      int
	CPUTimeTotal uint64
	CPUTimeDiff  uint64
}

// NewProcessMonitor returns an initialized ProcessMonitor ready for use.
func NewProcessMonitor() *ProcessMonitor {
	pm := &ProcessMonitor{}
	pm.Map = make(map[int]*Process)
	pm.NumCPUs = runtime.NumCPU()
	return pm
}

// Update updates the ProcessMonitor's state via the /proc filesystem.
func (pm *ProcessMonitor) Update() {
	lastCPUTimeTotal := pm.CPUTimeTotal
	pm.parseStatFile()
	pm.CPUTimeDiff = pm.CPUTimeTotal - lastCPUTimeTotal

	files, err := ioutil.ReadDir("/proc")
	if err != nil {
		panic(err)
	}

	// Mark all processes as Dead
	for _, p := range pm.List {
		p.Alive = false
	}

	for _, file := range files {
		if !file.IsDir() {
			continue
		}

		pid, err := strconv.Atoi(file.Name())
		if err != nil {
			continue // non-PID directory
		}

		if p, ok := pm.Map[pid]; ok {
			err := p.Update()
			if err == nil {
				p.Alive = true
			}
		} else {
			p := NewProcess(pid)
			if p != nil {
				p.Alive = true

				if !p.IsKernelThread() {
					pm.addProcess(p)
				}
			}
		}
	}

	pm.removeDeadProcesses()

	sort.Sort(ByCPUTimeDiff(pm.List))

	// sanity check
	if len(pm.List) != len(pm.Map) {
		panic("list and map are not in sync")
	}
}

func (pm *ProcessMonitor) addProcess(p *Process) {
	pm.List = append(pm.List, p)
	pm.Map[p.Pid] = p
}

func (pm *ProcessMonitor) removeDeadProcesses() {
	for i := len(pm.List) - 1; i >= 0; i-- {
		p := pm.List[i]

		if !p.Alive {
			pm.List = append(pm.List[:i], pm.List[i+1:]...)
			delete(pm.Map, p.Pid)
		}
	}
}

func (pm *ProcessMonitor) parseStatFile() {
	file, err := os.Open("/proc/stat")
	if err != nil {
		panic(err)
	}
	defer file.Close()

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		line := scanner.Text()
		if strings.HasPrefix(line, "cpu ") {
			pm.CPUTimeTotal = 0
			cpuTimeValues := strings.Split(line, " ")[2:] // skip "cpu" and ""
			for _, cpuTimeValue := range cpuTimeValues {
				value, err := strconv.ParseUint(cpuTimeValue, 10, 64)
				if err != nil {
					panic(err)
				}
				pm.CPUTimeTotal += value
			}
		}
	}
}
<commit_msg>Break after getting the data needed<commit_after>package main

import (
	"bufio"
	"io/ioutil"
	"os"
	"runtime"
	"sort"
	"strconv"
	"strings"
)

// ProcessMonitor keeps tracks of the processes running on the system.
type ProcessMonitor struct {
	List []*Process
	Map  map[int]*Process

	NumCPUs      int
	CPUTimeTotal uint64
	CPUTimeDiff  uint64
}

// NewProcessMonitor returns an initialized ProcessMonitor ready for use.
func NewProcessMonitor() *ProcessMonitor {
	pm := &ProcessMonitor{}
	pm.Map = make(map[int]*Process)
	pm.NumCPUs = runtime.NumCPU()
	return pm
}

// Update updates the ProcessMonitor's state via the /proc filesystem.
func (pm *ProcessMonitor) Update() {
	lastCPUTimeTotal := pm.CPUTimeTotal
	pm.parseStatFile()
	pm.CPUTimeDiff = pm.CPUTimeTotal - lastCPUTimeTotal

	files, err := ioutil.ReadDir("/proc")
	if err != nil {
		panic(err)
	}

	// Mark all processes as Dead
	for _, p := range pm.List {
		p.Alive = false
	}

	for _, file := range files {
		if !file.IsDir() {
			continue
		}

		pid, err := strconv.Atoi(file.Name())
		if err != nil {
			continue // non-PID directory
		}

		if p, ok := pm.Map[pid]; ok {
			err := p.Update()
			if err == nil {
				p.Alive = true
			}
		} else {
			p := NewProcess(pid)
			if p != nil {
				p.Alive = true

				if !p.IsKernelThread() {
					pm.addProcess(p)
				}
			}
		}
	}

	pm.removeDeadProcesses()

	sort.Sort(ByCPUTimeDiff(pm.List))

	// sanity check
	if len(pm.List) != len(pm.Map) {
		panic("list and map are not in sync")
	}
}

func (pm *ProcessMonitor) addProcess(p *Process) {
	pm.List = append(pm.List, p)
	pm.Map[p.Pid] = p
}

func (pm *ProcessMonitor) removeDeadProcesses() {
	for i := len(pm.List) - 1; i >= 0; i-- {
		p := pm.List[i]

		if !p.Alive {
			pm.List = append(pm.List[:i], pm.List[i+1:]...)
			delete(pm.Map, p.Pid)
		}
	}
}

func (pm *ProcessMonitor) parseStatFile() {
	file, err := os.Open("/proc/stat")
	if err != nil {
		panic(err)
	}
	defer file.Close()

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		line := scanner.Text()
		if strings.HasPrefix(line, "cpu ") {
			pm.CPUTimeTotal = 0
			cpuTimeValues := strings.Split(line, " ")[2:] // skip "cpu" and ""
			for _, cpuTimeValue := range cpuTimeValues {
				value, err := strconv.ParseUint(cpuTimeValue, 10, 64)
				if err != nil {
					panic(err)
				}
				pm.CPUTimeTotal += value
			}

			// Only parsing the first line for now, ignore rest of file.
			break
		}
	}
	if err := scanner.Err(); err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before>package discovery

import (
	"container/heap"
	"context"
	"errors"
	"math"
	"math/rand"
	"net/url"
	"time"

	"github.com/livepeer/go-livepeer/clog"
	"github.com/livepeer/go-livepeer/common"
	"github.com/livepeer/go-livepeer/monitor"
	"github.com/livepeer/go-livepeer/net"
	"github.com/livepeer/go-livepeer/server"

	"github.com/golang/glog"
)

var getOrchestratorsTimeoutLoop = 3 * time.Second
var getOrchestratorsCutoffTimeout = 500 * time.Millisecond
var maxGetOrchestratorCutoffTimeout = 6 * time.Second

var serverGetOrchInfo = server.GetOrchestratorInfo

type orchestratorPool struct {
	infos []common.OrchestratorLocalInfo
	pred  func(info *net.OrchestratorInfo) bool
	bcast common.Broadcaster
}

func NewOrchestratorPool(bcast common.Broadcaster, uris []*url.URL, score float32) *orchestratorPool {
	if len(uris) <= 0 {
		// Should we return here?
		glog.Error("Orchestrator pool does not have any URIs")
	}
	infos := make([]common.OrchestratorLocalInfo, 0, len(uris))
	for _, uri := range uris {
		infos = append(infos, common.OrchestratorLocalInfo{URL: uri, Score: score})
	}

	return &orchestratorPool{infos: infos, bcast: bcast}
}

func NewOrchestratorPoolWithPred(bcast common.Broadcaster, addresses []*url.URL,
	pred func(*net.OrchestratorInfo) bool, score float32) *orchestratorPool {

	pool := NewOrchestratorPool(bcast, addresses, score)
	pool.pred = pred
	return pool
}

func (o *orchestratorPool) GetInfos() []common.OrchestratorLocalInfo {
	return o.infos
}

func (o *orchestratorPool) GetInfo(uri string) common.OrchestratorLocalInfo {
	var res common.OrchestratorLocalInfo
	for _, info := range o.infos {
		if info.URL.String() == uri {
			res = info
			break
		}
	}
	return res
}

func (o *orchestratorPool) GetOrchestrators(ctx context.Context, numOrchestrators int, suspender common.Suspender, caps common.CapabilityComparator,
	scorePred common.ScorePred) ([]*net.OrchestratorInfo, error) {

	linfos := make([]common.OrchestratorLocalInfo, 0, len(o.infos))
	for _, info := range o.infos {
		if scorePred(info.Score) {
			linfos = append(linfos, info)
		}
	}

	numAvailableOrchs := len(linfos)
	numOrchestrators = int(math.Min(float64(numAvailableOrchs), float64(numOrchestrators)))

	// The following allows us to avoid capability check for jobs that only
	// depend on "legacy" features, since older orchestrators support these
	// features without capability discovery. This enables interop between
	// older orchestrators and newer orchestrators as long as the job only
	// requires the legacy feature set.
	//
	// When / if it's justified to completely break interop with older
	// orchestrators, then we can probably remove this check and work with
	// the assumption that all orchestrators support capability discovery.
	legacyCapsOnly := caps.LegacyOnly()

	isCompatible := func(info *net.OrchestratorInfo) bool {
		if o.pred != nil && !o.pred(info) {
			return false
		}
		// Legacy features already have support on the orchestrator.
		// Capabilities can be omitted in this case for older orchestrators.
		// Otherwise, capabilities are required to be present.
		if info.Capabilities == nil {
			if legacyCapsOnly {
				return true
			}
			return false
		}
		return caps.CompatibleWith(info.Capabilities)
	}
	getOrchInfo := func(ctx context.Context, uri *url.URL, infoCh chan *net.OrchestratorInfo, errCh chan error) {
		info, err := serverGetOrchInfo(ctx, o.bcast, uri)
		if err == nil && isCompatible(info) {
			infoCh <- info
			return
		}
		if err != nil && !errors.Is(err, context.Canceled) {
			clog.Errorf(ctx, "err=%q", err)
			if monitor.Enabled {
				monitor.LogDiscoveryError(ctx, uri.String(), err.Error())
			}
		}
		errCh <- err
	}

	// Shuffle into new slice to avoid mutating underlying data
	uris := make([]*url.URL, numAvailableOrchs)
	for i, j := range rand.Perm(numAvailableOrchs) {
		uris[i] = linfos[j].URL
	}

	var infos []*net.OrchestratorInfo
	var suspendedInfos *suspensionQueue
	var timedOut bool
	var nbResp int

	// try to discover orchestrators until at least 1 is found (with the exponential backoff timout)
	timeout := getOrchestratorsCutoffTimeout
	for {
		ctx, cancel := context.WithTimeout(clog.Clone(context.Background(), ctx), timeout)
		infoCh := make(chan *net.OrchestratorInfo, numAvailableOrchs)
		errCh := make(chan error, numAvailableOrchs)

		for _, uri := range uris {
			go getOrchInfo(ctx, uri, infoCh, errCh)
		}

		timedOut = false
		suspendedInfos = newSuspensionQueue()
		nbResp = 0
		for i := 0; i < numAvailableOrchs && len(infos) < numOrchestrators && !timedOut; i++ {
			select {
			case info := <-infoCh:
				if penalty := suspender.Suspended(info.Transcoder); penalty == 0 {
					infos = append(infos, info)
				} else {
					heap.Push(suspendedInfos, &suspension{info, penalty})
				}
				nbResp++
			case <-errCh:
				nbResp++
			case <-ctx.Done():
				timedOut = true
			}
		}
		cancel()

		if len(infos) > 0 {
			break
		}

		timeout *= 2
		if timeout >= maxGetOrchestratorCutoffTimeout {
			break
		}
		clog.V(common.DEBUG).Infof(ctx, "No orchestrators found, increasing discovery timeout to %s", timeout)
	}

	if len(infos) < numOrchestrators {
		diff := numOrchestrators - len(infos)
		for i := 0; i < diff && suspendedInfos.Len() > 0; i++ {
			info := heap.Pop(suspendedInfos).(*suspension).orch
			infos = append(infos, info)
		}
	}

	clog.Infof(ctx, "Done fetching orch info numOrch=%d responses=%d/%d timedOut=%t",
		len(infos), nbResp, len(uris), timedOut)
	return infos, nil
}

func (o *orchestratorPool) Size() int {
	return len(o.infos)
}

func (o *orchestratorPool) SizeWith(scorePred common.ScorePred) int {
	var size int
	for _, info := range o.infos {
		if scorePred(info.Score) {
			size++
		}
	}
	return size
}
<commit_msg>discovery: Fix dynamic timeout to not retry sending getOrchInfo request (but wait for the same req/res instead)<commit_after>package discovery

import (
	"container/heap"
	"context"
	"errors"
	"math"
	"math/rand"
	"net/url"
	"time"

	"github.com/livepeer/go-livepeer/clog"
	"github.com/livepeer/go-livepeer/common"
	"github.com/livepeer/go-livepeer/monitor"
	"github.com/livepeer/go-livepeer/net"
	"github.com/livepeer/go-livepeer/server"

	"github.com/golang/glog"
)

var getOrchestratorsTimeoutLoop = 3 * time.Second
var getOrchestratorsCutoffTimeout = 500 * time.Millisecond
var maxGetOrchestratorCutoffTimeout = 6 * time.Second

var serverGetOrchInfo = server.GetOrchestratorInfo

type orchestratorPool struct {
	infos []common.OrchestratorLocalInfo
	pred  func(info *net.OrchestratorInfo) bool
	bcast common.Broadcaster
}

func NewOrchestratorPool(bcast common.Broadcaster, uris []*url.URL, score float32) *orchestratorPool {
	if len(uris) <= 0 {
		// Should we return here?
		glog.Error("Orchestrator pool does not have any URIs")
	}
	infos := make([]common.OrchestratorLocalInfo, 0, len(uris))
	for _, uri := range uris {
		infos = append(infos, common.OrchestratorLocalInfo{URL: uri, Score: score})
	}

	return &orchestratorPool{infos: infos, bcast: bcast}
}

func NewOrchestratorPoolWithPred(bcast common.Broadcaster, addresses []*url.URL,
	pred func(*net.OrchestratorInfo) bool, score float32) *orchestratorPool {

	pool := NewOrchestratorPool(bcast, addresses, score)
	pool.pred = pred
	return pool
}

func (o *orchestratorPool) GetInfos() []common.OrchestratorLocalInfo {
	return o.infos
}

func (o *orchestratorPool) GetInfo(uri string) common.OrchestratorLocalInfo {
	var res common.OrchestratorLocalInfo
	for _, info := range o.infos {
		if info.URL.String() == uri {
			res = info
			break
		}
	}
	return res
}

func (o *orchestratorPool) GetOrchestrators(ctx context.Context, numOrchestrators int, suspender common.Suspender, caps common.CapabilityComparator,
	scorePred common.ScorePred) ([]*net.OrchestratorInfo, error) {

	linfos := make([]common.OrchestratorLocalInfo, 0, len(o.infos))
	for _, info := range o.infos {
		if scorePred(info.Score) {
			linfos = append(linfos, info)
		}
	}

	numAvailableOrchs := len(linfos)
	numOrchestrators = int(math.Min(float64(numAvailableOrchs), float64(numOrchestrators)))

	// The following allows us to avoid capability check for jobs that only
	// depend on "legacy" features, since older orchestrators support these
	// features without capability discovery. This enables interop between
	// older orchestrators and newer orchestrators as long as the job only
	// requires the legacy feature set.
	//
	// When / if it's justified to completely break interop with older
	// orchestrators, then we can probably remove this check and work with
	// the assumption that all orchestrators support capability discovery.
	legacyCapsOnly := caps.LegacyOnly()

	isCompatible := func(info *net.OrchestratorInfo) bool {
		if o.pred != nil && !o.pred(info) {
			return false
		}
		// Legacy features already have support on the orchestrator.
		// Capabilities can be omitted in this case for older orchestrators.
		// Otherwise, capabilities are required to be present.
		if info.Capabilities == nil {
			if legacyCapsOnly {
				return true
			}
			return false
		}
		return caps.CompatibleWith(info.Capabilities)
	}
	getOrchInfo := func(ctx context.Context, uri *url.URL, infoCh chan *net.OrchestratorInfo, errCh chan error) {
		info, err := serverGetOrchInfo(ctx, o.bcast, uri)
		if err == nil && isCompatible(info) {
			infoCh <- info
			return
		}
		if err != nil && !errors.Is(err, context.Canceled) {
			clog.Errorf(ctx, "err=%q", err)
			if monitor.Enabled {
				monitor.LogDiscoveryError(ctx, uri.String(), err.Error())
			}
		}
		errCh <- err
	}

	// Shuffle into new slice to avoid mutating underlying data
	uris := make([]*url.URL, numAvailableOrchs)
	for i, j := range rand.Perm(numAvailableOrchs) {
		uris[i] = linfos[j].URL
	}

	var infos []*net.OrchestratorInfo
	suspendedInfos := newSuspensionQueue()
	timedOut := false
	nbResp := 0
	infoCh := make(chan *net.OrchestratorInfo, numAvailableOrchs)
	errCh := make(chan error, numAvailableOrchs)

	ctx, cancel := context.WithTimeout(clog.Clone(context.Background(), ctx), maxGetOrchestratorCutoffTimeout)
	for _, uri := range uris {
		go getOrchInfo(ctx, uri, infoCh, errCh)
	}

	// try to wait for orchestrators until at least 1 is found (with the exponential backoff timout)
	timeout := getOrchestratorsCutoffTimeout
	timer := time.NewTimer(timeout)

	for nbResp < numAvailableOrchs && len(infos) < numOrchestrators && !timedOut {
		select {
		case info := <-infoCh:
			if penalty := suspender.Suspended(info.Transcoder); penalty == 0 {
				infos = append(infos, info)
			} else {
				heap.Push(suspendedInfos, &suspension{info, penalty})
			}
			nbResp++
		case <-errCh:
			nbResp++
		case <-timer.C:
			if len(infos) > 0 {
				timedOut = true
			}

			// At this point we already waited timeout, so need to wait another timeout to make it the increased 2 * timeout
			timer.Reset(timeout)
			timeout *= 2
			if timeout > maxGetOrchestratorCutoffTimeout {
				timeout = maxGetOrchestratorCutoffTimeout
			}
			clog.V(common.DEBUG).Infof(ctx, "No orchestrators found, increasing discovery timeout to %s", timeout)
		case <-ctx.Done():
			timedOut = true
		}
	}
	cancel()

	if len(infos) < numOrchestrators {
		diff := numOrchestrators - len(infos)
		for i := 0; i < diff && suspendedInfos.Len() > 0; i++ {
			info := heap.Pop(suspendedInfos).(*suspension).orch
			infos = append(infos, info)
		}
	}

	clog.Infof(ctx, "Done fetching orch info numOrch=%d responses=%d/%d timedOut=%t",
		len(infos), nbResp, len(uris), timedOut)
	return infos, nil
}

func (o *orchestratorPool) Size() int {
	return len(o.infos)
}

func (o *orchestratorPool) SizeWith(scorePred common.ScorePred) int {
	var size int
	for _, info := range o.infos {
		if scorePred(info.Score) {
			size++
		}
	}
	return size
}
<|endoftext|>


<commit_before>package program

// Version can be requested through the command line with:
//
//     c2go -v
//
// See https://github.com/elliotchance/c2go/wiki/Release-Process
const Version = "v0.21.17 Zinc 2018-04-05"
<commit_msg>Bump version: v0.21.18 Zinc 2018-04-06<commit_after>package program

// Version can be requested through the command line with:
//
//     c2go -v
//
// See https://github.com/elliotchance/c2go/wiki/Release-Process
const Version = "v0.21.18 Zinc 2018-04-06"
<|endoftext|>


<commit_before>package extnet

import (
	"io"
	"net"
	"time"
	"unsafe"
)

// SCTPConn is an implementation of the Conn interface for SCTP network connections.
type SCTPConn struct {
	l      *SCTPListener
	id     assocT
	r      *io.PipeReader
	addr   net.Addr
	wdline time.Time
	rdline *time.Timer
}

func (c *SCTPConn) Read(b []byte) (int, error) {
	return c.r.Read(b)
}

func (c *SCTPConn) Write(b []byte) (int, error) {
	return c.send(b, 0)
}

// Close closes the connection.
func (c *SCTPConn) Close() error {
	_, e := c.send([]byte{}, sctpEoF)
	return e
}

// Abort closes the connection with abort message.
func (c *SCTPConn) Abort(reason string) error {
	_, e := c.send([]byte(reason), sctpAbort)
	return e
}

func (c *SCTPConn) send(b []byte, flag uint16) (int, error) {
	info := sndrcvInfo{}
	info.flags = flag
	info.assocID = c.id
	return sctpSend(c.l.sock, b, &info, 0)
}

// LocalAddr returns the local network address.
func (c *SCTPConn) LocalAddr() net.Addr {
	return c.l.addr
}

// RemoteAddr returns the remote network address.
func (c *SCTPConn) RemoteAddr() net.Addr {
	return c.addr
}

// SetDeadline implements the Conn SetDeadline method.
func (c *SCTPConn) SetDeadline(t time.Time) (e error) {
	e = c.SetReadDeadline(t)
	if e != nil {
		return
	}
	e = c.SetWriteDeadline(t)
	return
}

// SetReadDeadline implements the Conn SetReadDeadline method.
func (c *SCTPConn) SetReadDeadline(t time.Time) error {
	if c.rdline != nil {
		c.rdline.Stop()
	}
	if !t.IsZero() {
		c.rdline = time.AfterFunc(t.Sub(time.Now()), func() {
			c.l.pipes[c.id].Close()
		})
	}
	return nil
}

// SetWriteDeadline implements the Conn SetWriteDeadline method.
func (c *SCTPConn) SetWriteDeadline(t time.Time) error {
	c.wdline = t
	return nil
}

// DialSCTP connects from the local address laddr to the remote address raddr.
func DialSCTP(laddr, raddr *SCTPAddr) (c *SCTPConn, e error) {
	sock, e := bindsocket(laddr)
	if e != nil {
		return nil, e
	}

	// create listener
	l := &SCTPListener{}
	l.sock = sock
	l.addr = laddr
	l.pipes = make(map[assocT]*io.PipeWriter)
	l.accept = make(chan *SCTPConn, 1)

	// start reading buffer
	go read(l)

	e = l.ConnectSCTP(raddr)
	if e != nil {
		return nil, e
	}
	c = <-l.accept
	close(l.accept)
	l.accept = nil

	return
}

type rtoinfo struct {
	assocID assocT
	ini     uint32
	max     uint32
	min     uint32
}

// SetRtoInfo set retransmit timer options
func (c *SCTPConn) SetRtoInfo(ini, min, max int) error {
	attr := rtoinfo{
		assocID: c.id,
		ini:     uint32(ini),
		max:     uint32(max),
		min:     uint32(min)}
	l := unsafe.Sizeof(attr)
	p := unsafe.Pointer(&attr)

	return setSockOpt(c.l.sock, sctpRtoInfo, p, l)
}

type assocparams struct {
	assocID     assocT
	pRwnd       uint32
	lRwnd       uint32
	cLife       uint32
	assocMaxRxt uint16
	numPeerDest uint16
}

// SetAssocinfo set association parameter
func (c *SCTPConn) SetAssocinfo(pRwnd, lRwnd, cLife, assocMaxRxt, numPeerDest int) error {
	attr := assocparams{
		assocID:     c.id,
		pRwnd:       uint32(pRwnd),
		lRwnd:       uint32(lRwnd),
		cLife:       uint32(cLife),
		assocMaxRxt: uint16(assocMaxRxt),
		numPeerDest: uint16(numPeerDest)}
	l := unsafe.Sizeof(attr)
	p := unsafe.Pointer(&attr)

	return setSockOpt(c.l.sock, sctpAssocInfo, p, l)
}

// SetNodelay set delay answer or not
func (c *SCTPConn) SetNodelay(attr bool) error {
	l := unsafe.Sizeof(attr)
	p := unsafe.Pointer(&attr)

	return setSockOpt(c.l.sock, sctpNodelay, p, l)
}

/*
const (
	HB_ENABLE         = uint32(C.SPP_HB_ENABLE)
	HB_DISABLE        = uint32(C.SPP_HB_DISABLE)
	HB_DEMAND         = uint32(C.SPP_HB_DEMAND)
	PMTUD_ENABLE      = uint32(C.SPP_PMTUD_ENABLE)
	PMTUD_DISABLE     = uint32(C.SPP_PMTUD_DISABLE)
	SACKDELAY_ENABLE  = uint32(C.SPP_SACKDELAY_ENABLE)
	SACKDELAY_DISABLE = uint32(C.SPP_SACKDELAY_DISABLE)
	HB_TIME_IS_ZERO   = uint32(C.SPP_HB_TIME_IS_ZERO)
)

func (c *SCTPConn) SetPeerAddrParams(
	hbinterval uint32, pathmaxrxt uint16, pathmtu, sackdelay, flags uint32) error {
	attr := C.struct_sctp_paddrparams{}
	l := C.socklen_t(unsafe.Sizeof(attr))

	attr.spp_assoc_id = c.id
	attr.spp_hbinterval = C.__u32(hbinterval)
	attr.spp_pathmaxrxt = C.__u16(pathmaxrxt)
	//attr.spp_pathmtu = C.__u32(pathmtu)
	//attr.spp_sackdelay = C.__u32(sackdelay)
	//attr.spp_flags = C.__u32(flags)

	p := unsafe.Pointer(&attr)
	i, e := C.setsockopt(c.sock, C.SOL_SCTP, C.SCTP_PEER_ADDR_PARAMS, p, l)
	if int(i) < 0 {
		return e
	}
	return nil
}
*/
<commit_msg>modify<commit_after>package extnet

import (
	"io"
	"net"
	"sync"
	"time"
	"unsafe"
)

// SCTPConn is an implementation of the Conn interface for SCTP network connections.
type SCTPConn struct {
	l    *SCTPListener
	id   assocT
	addr net.Addr

	buf []byte
	win []byte
	err error
	lk  sync.Mutex
	wt  sync.Cond

	r *io.PipeReader

	wdline time.Time
	rdline *time.Timer
}

type notify struct {
	size int
}

func (n notify) Error() string {
	return "data buffer notification"
}

func (c *SCTPConn) Read(b []byte) (int, error) {
	c.lk.Lock()
	defer c.lk.Unlock()

	for {
		if c.err != nil {
			return 0, c.err
		}
		if len(c.win) != 0 {
			break
		}
		c.wt.Wait()
	}
	n := copy(b, c.win)
	c.win = c.win[n:]
	return n, nil
}

func (c *SCTPConn) cache(b []byte) {
	c.lk.Lock()
	defer c.lk.Unlock()

	if len(c.win) == 0 {
		c.win = c.buf[:0]
	}
	c.win = append(c.win, b...)
	c.wt.Signal()
}

func (c *SCTPConn) Write(b []byte) (int, error) {
	return c.send(b, 0)
}

// Close closes the connection.
func (c *SCTPConn) Close() error {
	_, e := c.send([]byte{}, sctpEoF)
	return e
}

// Abort closes the connection with abort message.
func (c *SCTPConn) Abort(reason string) error {
	_, e := c.send([]byte(reason), sctpAbort)
	return e
}

func (c *SCTPConn) send(b []byte, flag uint16) (int, error) {
	info := sndrcvInfo{}
	info.flags = flag
	info.assocID = c.id
	return sctpSend(c.l.sock, b, &info, 0)
}

// LocalAddr returns the local network address.
func (c *SCTPConn) LocalAddr() net.Addr {
	return c.l.addr
}

// RemoteAddr returns the remote network address.
func (c *SCTPConn) RemoteAddr() net.Addr {
	return c.addr
}

// SetDeadline implements the Conn SetDeadline method.
func (c *SCTPConn) SetDeadline(t time.Time) (e error) {
	e = c.SetReadDeadline(t)
	if e != nil {
		return
	}
	e = c.SetWriteDeadline(t)
	return
}

// SetReadDeadline implements the Conn SetReadDeadline method.
func (c *SCTPConn) SetReadDeadline(t time.Time) error {
	if c.rdline != nil {
		c.rdline.Stop()
	}
	if !t.IsZero() {
		c.rdline = time.AfterFunc(t.Sub(time.Now()), func() {
			c.l.pipes[c.id].Close()
		})
	}
	return nil
}

// SetWriteDeadline implements the Conn SetWriteDeadline method.
func (c *SCTPConn) SetWriteDeadline(t time.Time) error {
	c.wdline = t
	return nil
}

// DialSCTP connects from the local address laddr to the remote address raddr.
func DialSCTP(laddr, raddr *SCTPAddr) (c *SCTPConn, e error) {
	sock, e := bindsocket(laddr)
	if e != nil {
		return nil, e
	}

	// create listener
	l := &SCTPListener{}
	l.sock = sock
	l.addr = laddr
	l.pipes = make(map[assocT]*io.PipeWriter)
	l.accept = make(chan *SCTPConn, 1)

	// start reading buffer
	go read(l)

	e = l.ConnectSCTP(raddr)
	if e != nil {
		return nil, e
	}
	c = <-l.accept
	close(l.accept)
	l.accept = nil

	return
}

type rtoinfo struct {
	assocID assocT
	ini     uint32
	max     uint32
	min     uint32
}

// SetRtoInfo set retransmit timer options
func (c *SCTPConn) SetRtoInfo(ini, min, max int) error {
	attr := rtoinfo{
		assocID: c.id,
		ini:     uint32(ini),
		max:     uint32(max),
		min:     uint32(min)}
	l := unsafe.Sizeof(attr)
	p := unsafe.Pointer(&attr)

	return setSockOpt(c.l.sock, sctpRtoInfo, p, l)
}

type assocparams struct {
	assocID     assocT
	pRwnd       uint32
	lRwnd       uint32
	cLife       uint32
	assocMaxRxt uint16
	numPeerDest uint16
}

// SetAssocinfo set association parameter
func (c *SCTPConn) SetAssocinfo(pRwnd, lRwnd, cLife, assocMaxRxt, numPeerDest int) error {
	attr := assocparams{
		assocID:     c.id,
		pRwnd:       uint32(pRwnd),
		lRwnd:       uint32(lRwnd),
		cLife:       uint32(cLife),
		assocMaxRxt: uint16(assocMaxRxt),
		numPeerDest: uint16(numPeerDest)}
	l := unsafe.Sizeof(attr)
	p := unsafe.Pointer(&attr)

	return setSockOpt(c.l.sock, sctpAssocInfo, p, l)
}

// SetNodelay set delay answer or not
func (c *SCTPConn) SetNodelay(attr bool) error {
	l := unsafe.Sizeof(attr)
	p := unsafe.Pointer(&attr)

	return setSockOpt(c.l.sock, sctpNodelay, p, l)
}

/*
const (
	HB_ENABLE         = uint32(C.SPP_HB_ENABLE)
	HB_DISABLE        = uint32(C.SPP_HB_DISABLE)
	HB_DEMAND         = uint32(C.SPP_HB_DEMAND)
	PMTUD_ENABLE      = uint32(C.SPP_PMTUD_ENABLE)
	PMTUD_DISABLE     = uint32(C.SPP_PMTUD_DISABLE)
	SACKDELAY_ENABLE  = uint32(C.SPP_SACKDELAY_ENABLE)
	SACKDELAY_DISABLE = uint32(C.SPP_SACKDELAY_DISABLE)
	HB_TIME_IS_ZERO   = uint32(C.SPP_HB_TIME_IS_ZERO)
)

func (c *SCTPConn) SetPeerAddrParams(
	hbinterval uint32, pathmaxrxt uint16, pathmtu, sackdelay, flags uint32) error {
	attr := C.struct_sctp_paddrparams{}
	l := C.socklen_t(unsafe.Sizeof(attr))

	attr.spp_assoc_id = c.id
	attr.spp_hbinterval = C.__u32(hbinterval)
	attr.spp_pathmaxrxt = C.__u16(pathmaxrxt)
	//attr.spp_pathmtu = C.__u32(pathmtu)
	//attr.spp_sackdelay = C.__u32(sackdelay)
	//attr.spp_flags = C.__u32(flags)

	p := unsafe.Pointer(&attr)
	i, e := C.setsockopt(c.sock, C.SOL_SCTP, C.SCTP_PEER_ADDR_PARAMS, p, l)
	if int(i) < 0 {
		return e
	}
	return nil
}
*/
<|endoftext|>


<commit_before>package buildchain

import (
	"encoding/json"
	"fmt"
	"sync"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
	cmdutil "github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/cmd/util"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
	dot "github.com/awalterschulze/gographviz"
	"github.com/golang/glog"
	"github.com/spf13/cobra"

	buildapi "github.com/openshift/origin/pkg/build/api"
	"github.com/openshift/origin/pkg/cmd/util/clientcmd"
	imageapi "github.com/openshift/origin/pkg/image/api"
)

const longDescription = `Output build dependencies of a specific image repository.
Supported output formats are json, dot, and ast. The default is set to json.
Tag and namespace are optional and if they are not specified, 'latest' and the
default namespace will be used respectively.

Examples:

    # Build dependency tree for the specified image repository and tag
    $ openshift ex build-chain [image-repository]:[tag]

    # Build dependency trees for all tags in the specified image repository
    $ openshift ex build-chain [image-repository] --all-tags

    # Build the dependency tree using tag 'latest' in 'testing' namespace
    $ openshift ex build-chain [image-repository] -n testing

    # Build the dependency tree and output it in DOT syntax
    $ openshift ex build-chain [image-repository] -o dot

    # Build dependency trees for all image repositories in the current namespace
    $ openshift ex build-chain

    # Build dependency trees for all image repositories across all namespaces
    $ openshift ex build-chain --all
`

// ImageRepo is a representation of a node inside a tree
type ImageRepo struct {
	FullName string       `json:"fullname"`
	Tags     []string     `json:"tags,omitempty"`
	Edges    []*Edge      `json:"edges,omitempty"`
	Children []*ImageRepo `json:"children,omitempty"`
}

// String helps in dumping a tree in AST format
func (root *ImageRepo) String() string {
	tree := ""
	tree += root.FullName

	for _, n := range root.Children {
		tree += "(" + n.String() + ")"
	}

	return tree
}

// Edge represents a build configuration relationship
// between two nodes
//
// Note that this type has no relation with the dot.Edge
// type
type Edge struct {
	FullName string `json:"fullname"`
	To       string `json:"to"`
}

// NewEdge adds a new edge on a parent node
//
// Note that this function has no relation
// with the dot.Edge type
func NewEdge(fullname, to string) *Edge {
	return &Edge{
		FullName: fullname,
		To:       to,
	}
}

// NewCmdBuildChain implements all the necessary functionality for the build-chain module
func NewCmdBuildChain(f *clientcmd.Factory, parentName, name string) *cobra.Command {
	cmd := &cobra.Command{
		Use:   fmt.Sprintf("%s [image-repository]:[tag]", name),
		Short: "Output build dependencies of a specific image repository",
		Long:  longDescription,
		Run: func(cmd *cobra.Command, args []string) {
			all := cmdutil.GetFlagBool(cmd, "all")
			allTags := cmdutil.GetFlagBool(cmd, "all-tags")
			if len(args) > 1 ||
				(len(args) == 1 && all) ||
				(len(args) == 0 && allTags) ||
				(all && allTags) {
				usageError(cmd, "Must pass nothing, an image repository name:tag combination, or specify the --all flag")
			}

			osc, kc, err := f.Clients()
			checkErr(err)

			// Retrieve namespace(s)
			namespace := cmdutil.GetFlagString(cmd, "namespace")
			namespaces := make([]string, 0)
			switch all {
			case true:
				nsList, err := kc.Namespaces().List(labels.Everything())
				checkErr(err)
				for _, ns := range nsList.Items {
					namespaces = append(namespaces, ns.Name)
				}
			case false:
				namespaces = append(namespaces, namespace)
			}

			// Get all build configurations
			buildConfigList := make([]buildapi.BuildConfig, 0)
			for _, namespace := range namespaces {
				cfgList, err := osc.BuildConfigs(namespace).List(labels.Everything(), fields.Everything())
				checkErr(err)
				buildConfigList = append(buildConfigList, cfgList.Items...)
			}

			// Parse user input and validate specified image repository
			repos := make(map[string][]string)
			if !all && len(args) != 0 {
				name, tag, err := parseTag(args[0])
				checkErr(err)

				// Validate the specified image repository
				imgRepo, err := osc.ImageRepositories(namespace).Get(name)
				checkErr(err)

				tags := make([]string, 0)
				if allTags {
					for tag := range imgRepo.Tags {
						tags = append(tags, tag)
					}
				} else {
					tags = []string{tag}
				}

				repo := join(namespace, name)
				// Set the specified repo as the only one to output dependencies for
				repos[repo] = tags
			} else {
				// Get all image repositories from build configurations
				repos = getRepos(buildConfigList)

				// Make sure from now on that the --all flag is true
				// since we are building dependency trees for every
				// image repository available either in the current
				// namespace or in every namespace
				all = true
			}

			if len(repos) == 0 {
				checkErr(fmt.Errorf("no image repository available in '%s' namespace for building its dependency tree", namespace))
			}

			output := cmdutil.GetFlagString(cmd, "output")
			for repo, tags := range repos {
				for _, tag := range tags {
					root, err := findRepoDeps(repo, tag, all, buildConfigList)
					checkErr(err)

					// Check if the given image repository doesn't have any dependencies
					if treeSize(root) < 2 {
						glog.Infof("%s:%s has no dependencies\n", root.FullName, tag)
						continue
					}

					switch output {
					case "json":
						jsonDump, err := json.MarshalIndent(root, "", "\t")
						checkErr(err)
						fmt.Println(string(jsonDump))
					case "dot":
						g := dot.NewGraph()
						_, name, err := split(repo)
						checkErr(err)
						graphName := validDOT(name)
						g.SetName(graphName)
						// Directed graph since we illustrate dependencies
						g.SetDir(true)
						// Explicitly allow multiple pairs of edges between
						// the same pair of nodes
						g.SetStrict(false)
						fmt.Println(dotDump(root, g, graphName))
					case "ast":
						fmt.Println(root)
					default:
						usageError(cmd, "Wrong output format specified: %s", output)
					}
				}
			}
		},
	}

	cmd.Flags().Bool("all", false, "Build dependency trees for all image repositories")
	cmd.Flags().Bool("all-tags", false, "Build dependency trees for all tags of a specific image repository")
	cmd.Flags().StringP("output", "o", "json", "Output format of dependency tree(s)")
	return cmd
}

// getRepos iterates over a given set of build configurations
// and extracts all the image repositories which trigger a
// build when the image repository is updated
func getRepos(configs []buildapi.BuildConfig) map[string][]string {
	avoidDuplicates := make(map[string][]string)
	for _, cfg := range configs {
		for _, tr := range cfg.Triggers {
			if tr.ImageChange != nil && tr.ImageChange.From.Name != "" {
				var repo string
				switch tr.ImageChange.From.Namespace {
				case "":
					repo = join(cfg.Namespace, tr.ImageChange.From.Name)
				default:
					repo = join(tr.ImageChange.From.Namespace, tr.ImageChange.From.Name)
				}

				var tag string
				switch tr.ImageChange.Tag {
				case "":
					tag = "latest"
				default:
					tag = tr.ImageChange.Tag
				}

				uniqueTag := true
				for _, prev := range avoidDuplicates[repo] {
					if prev == tag {
						uniqueTag = false
						break
					}
				}
				if uniqueTag {
					avoidDuplicates[repo] = append(avoidDuplicates[repo], tag)
				}
			}
		}
	}

	return avoidDuplicates
}

// findRepoDeps accepts an image repository and a list of build
// configurations and returns the dependency tree of the specified
// image repository
func findRepoDeps(repo, tag string, all bool, buildConfigList []buildapi.BuildConfig) (*ImageRepo, error) {
	root := &ImageRepo{
		FullName: repo,
		Tags:     []string{tag},
	}

	namespace, name, err := split(repo)
	if err != nil {
		return nil, err
	}

	// Search all build configurations in order to find the image
	// repositories depending on the specified image repository
	var childNamespace, childName, childTag string
	for _, cfg := range buildConfigList {
		for _, tr := range cfg.Triggers {
			// Setup zeroed fields to their default values
			if tr.ImageChange != nil && tr.ImageChange.From.Namespace == "" {
				tr.ImageChange.From.Namespace = cfg.Namespace
			}
			if tr.ImageChange != nil && tr.ImageChange.Tag == "" {
				tr.ImageChange.Tag = "latest"
			}

			if tr.ImageChange != nil &&
				namespace == tr.ImageChange.From.Namespace &&
				name == tr.ImageChange.From.Name &&
				tag == tr.ImageChange.Tag {

				// Either To & Tag or DockerImageReference will be used as output
				if cfg.Parameters.Output.To != nil && cfg.Parameters.Output.To.Name != "" {
					childName = cfg.Parameters.Output.To.Name
					childTag = cfg.Parameters.Output.Tag
					if cfg.Parameters.Output.To.Namespace != "" {
						childNamespace = cfg.Parameters.Output.To.Namespace
					} else {
						childNamespace = cfg.Namespace
					}
				} else {
					ref, err := imageapi.ParseDockerImageReference(cfg.Parameters.Output.DockerImageReference)
					if err != nil {
						return nil, err
					}
					childName = ref.Name
					childTag = ref.Tag
					childNamespace = cfg.Namespace
				}

				childRepo := join(childNamespace, childName)

				// Build all children and their dependency trees recursively
				child, err := findRepoDeps(childRepo, childTag, all, buildConfigList)
				if err != nil {
					return nil, err
				}

				// Add edge between root and child
				cfgFullName := join(cfg.Namespace, cfg.Name)
				root.Edges = append(root.Edges, NewEdge(cfgFullName, child.FullName))

				// If the child depends on root via more than one tag, we have to make sure
				// that only one single instance of the child will make it into root.Children
				cont := false
				for _, repo := range root.Children {
					if repo.FullName == child.FullName {
						// Just pass the tag along and discard the current child
						repo.Tags = append(repo.Tags, child.Tags...)
						cont = true
						break
					}
				}
				if cont {
					// Do not append this child in root.Children. It's already in there
					continue
				}

				root.Children = append(root.Children, child)
			}
		}
	}

	return root, nil
}

var once sync.Once

// dotDump dumps the given image repository tree in DOT syntax
func dotDump(root *ImageRepo, g *dot.Graph, graphName string) string {
	if root == nil {
		return ""
	}

	// Add current node
	rootNamespace, rootName, err := split(root.FullName)
	checkErr(err)
	attrs := make(map[string]string)
	for _, tag := range root.Tags {
		setTag(tag, attrs)
	}
	var tag string
	// Inject tag into root's name
	once.Do(func() {
		tag = root.Tags[0]
	})
	setLabel(rootName, rootNamespace, attrs, tag)
	rootName = validDOT(rootName)
	g.AddNode(graphName, rootName, attrs)

	// Add edges between current node and its children
	for _, child := range root.Children {
		for _, edge := range root.Edges {
			if child.FullName == edge.To {
				_, childName, err := split(child.FullName)
				checkErr(err)
				childName = validDOT(childName)
				edgeNamespace, edgeName, err := split(edge.FullName)
				checkErr(err)
				edgeName = validDOT(edgeName)

				edgeAttrs := make(map[string]string)
				setLabel(edgeName, edgeNamespace, edgeAttrs, "")
				g.AddEdge(rootName, childName, true, edgeAttrs)
			}
		}
		// Recursively add every child and their children as nodes
		dotDump(child, g, graphName)
	}

	dotOutput := g.String()

	// Parse DOT output for validation
	if _, err := dot.Parse([]byte(dotOutput)); err != nil {
		checkErr(fmt.Errorf("cannot parse DOT output: %v\n", err))
	}

	return dotOutput
}
<commit_msg>build-chain: Fix default namespace setup<commit_after>package buildchain

import (
	"encoding/json"
	"fmt"
	"sync"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
	cmdutil "github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/cmd/util"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
	dot "github.com/awalterschulze/gographviz"
	"github.com/golang/glog"
	"github.com/spf13/cobra"

	buildapi "github.com/openshift/origin/pkg/build/api"
	"github.com/openshift/origin/pkg/cmd/util/clientcmd"
	imageapi "github.com/openshift/origin/pkg/image/api"
)

const longDescription = `Output build dependencies of a specific image repository.
Supported output formats are json, dot, and ast. The default is set to json.
Tag and namespace are optional and if they are not specified, 'latest' and the
default namespace will be used respectively.

Examples:

    # Build dependency tree for the specified image repository and tag
    $ openshift ex build-chain [image-repository]:[tag]

    # Build dependency trees for all tags in the specified image repository
    $ openshift ex build-chain [image-repository] --all-tags

    # Build the dependency tree using tag 'latest' in 'testing' namespace
    $ openshift ex build-chain [image-repository] -n testing

    # Build the dependency tree and output it in DOT syntax
    $ openshift ex build-chain [image-repository] -o dot

    # Build dependency trees for all image repositories in the current namespace
    $ openshift ex build-chain

    # Build dependency trees for all image repositories across all namespaces
    $ openshift ex build-chain --all
`

// ImageRepo is a representation of a node inside a tree
type ImageRepo struct {
	FullName string       `json:"fullname"`
	Tags     []string     `json:"tags,omitempty"`
	Edges    []*Edge      `json:"edges,omitempty"`
	Children []*ImageRepo `json:"children,omitempty"`
}

// String helps in dumping a tree in AST format
func (root *ImageRepo) String() string {
	tree := ""
	tree += root.FullName

	for _, n := range root.Children {
		tree += "(" + n.String() + ")"
	}

	return tree
}

// Edge represents a build configuration relationship
// between two nodes
//
// Note that this type has no relation with the dot.Edge
// type
type Edge struct {
	FullName string `json:"fullname"`
	To       string `json:"to"`
}

// NewEdge adds a new edge on a parent node
//
// Note that this function has no relation
// with the dot.Edge type
func NewEdge(fullname, to string) *Edge {
	return &Edge{
		FullName: fullname,
		To:       to,
	}
}

// NewCmdBuildChain implements all the necessary functionality for the build-chain module
func NewCmdBuildChain(f *clientcmd.Factory, parentName, name string) *cobra.Command {
	cmd := &cobra.Command{
		Use:   fmt.Sprintf("%s [image-repository]:[tag]", name),
		Short: "Output build dependencies of a specific image repository",
		Long:  longDescription,
		Run: func(cmd *cobra.Command, args []string) {
			all := cmdutil.GetFlagBool(cmd, "all")
			allTags := cmdutil.GetFlagBool(cmd, "all-tags")
			if len(args) > 1 ||
				(len(args) == 1 && all) ||
				(len(args) == 0 && allTags) ||
				(all && allTags) {
				usageError(cmd, "Must pass nothing, an image repository name:tag combination, or specify the --all flag")
			}

			osc, kc, err := f.Clients()
			checkErr(err)

			// Retrieve namespace(s)
			namespace := cmdutil.GetFlagString(cmd, "namespace")
			namespaces := make([]string, 0)
			switch all {
			case true:
				nsList, err := kc.Namespaces().List(labels.Everything())
				checkErr(err)
				for _, ns := range nsList.Items {
					namespaces = append(namespaces, ns.Name)
				}
			case false:
				if len(namespace) == 0 {
					namespace, err = f.DefaultNamespace()
					checkErr(err)
				}
				namespaces = append(namespaces, namespace)
			}

			// Get all build configurations
			buildConfigList := make([]buildapi.BuildConfig, 0)
			for _, namespace := range namespaces {
				cfgList, err := osc.BuildConfigs(namespace).List(labels.Everything(), fields.Everything())
				checkErr(err)
				buildConfigList = append(buildConfigList, cfgList.Items...)
			}

			// Parse user input and validate specified image repository
			repos := make(map[string][]string)
			if !all && len(args) != 0 {
				name, tag, err := parseTag(args[0])
				checkErr(err)

				// Validate the specified image repository
				imgRepo, err := osc.ImageRepositories(namespace).Get(name)
				checkErr(err)

				tags := make([]string, 0)
				if allTags {
					for tag := range imgRepo.Tags {
						tags = append(tags, tag)
					}
				} else {
					tags = []string{tag}
				}

				repo := join(namespace, name)
				// Set the specified repo as the only one to output dependencies for
				repos[repo] = tags
			} else {
				// Get all image repositories from build configurations
				repos = getRepos(buildConfigList)

				// Make sure from now on that the --all flag is true
				// since we are building dependency trees for every
				// image repository available either in the current
				// namespace or in every namespace
				all = true
			}

			if len(repos) == 0 {
				checkErr(fmt.Errorf("no image repository available in '%s' namespace for building its dependency tree", namespace))
			}

			output := cmdutil.GetFlagString(cmd, "output")
			for repo, tags := range repos {
				for _, tag := range tags {
					root, err := findRepoDeps(repo, tag, all, buildConfigList)
					checkErr(err)

					// Check if the given image repository doesn't have any dependencies
					if treeSize(root) < 2 {
						glog.Infof("%s:%s has no dependencies\n", root.FullName, tag)
						continue
					}

					switch output {
					case "json":
						jsonDump, err := json.MarshalIndent(root, "", "\t")
						checkErr(err)
						fmt.Println(string(jsonDump))
					case "dot":
						g := dot.NewGraph()
						_, name, err := split(repo)
						checkErr(err)
						graphName := validDOT(name)
						g.SetName(graphName)
						// Directed graph since we illustrate dependencies
						g.SetDir(true)
						// Explicitly allow multiple pairs of edges between
						// the same pair of nodes
						g.SetStrict(false)
						fmt.Println(dotDump(root, g, graphName))
					case "ast":
						fmt.Println(root)
					default:
						usageError(cmd, "Wrong output format specified: %s", output)
					}
				}
			}
		},
	}

	cmd.Flags().Bool("all", false, "Build dependency trees for all image repositories")
	cmd.Flags().Bool("all-tags", false, "Build dependency trees for all tags of a specific image repository")
	cmd.Flags().StringP("output", "o", "json", "Output format of dependency tree(s)")
	return cmd
}

// getRepos iterates over a given set of build configurations
// and extracts all the image repositories which trigger a
// build when the image repository is updated
func getRepos(configs []buildapi.BuildConfig) map[string][]string {
	avoidDuplicates := make(map[string][]string)
	for _, cfg := range configs {
		for _, tr := range cfg.Triggers {
			if tr.ImageChange != nil && tr.ImageChange.From.Name != "" {
				var repo string
				switch tr.ImageChange.From.Namespace {
				case "":
					repo = join(cfg.Namespace, tr.ImageChange.From.Name)
				default:
					repo = join(tr.ImageChange.From.Namespace, tr.ImageChange.From.Name)
				}

				var tag string
				switch tr.ImageChange.Tag {
				case "":
					tag = "latest"
				default:
					tag = tr.ImageChange.Tag
				}

				uniqueTag := true
				for _, prev := range avoidDuplicates[repo] {
					if prev == tag {
						uniqueTag = false
						break
					}
				}
				if uniqueTag {
					avoidDuplicates[repo] = append(avoidDuplicates[repo], tag)
				}
			}
		}
	}

	return avoidDuplicates
}

// findRepoDeps accepts an image repository and a list of build
// configurations and returns the dependency tree of the specified
// image repository
func findRepoDeps(repo, tag string, all bool, buildConfigList []buildapi.BuildConfig) (*ImageRepo, error) {
	root := &ImageRepo{
		FullName: repo,
		Tags:     []string{tag},
	}

	namespace, name, err := split(repo)
	if err != nil {
		return nil, err
	}

	// Search all build configurations in order to find the image
	// repositories depending on the specified image repository
	var childNamespace, childName, childTag string
	for _, cfg := range buildConfigList {
		for _, tr := range cfg.Triggers {
			// Setup zeroed fields to their default values
			if tr.ImageChange != nil && tr.ImageChange.From.Namespace == "" {
				tr.ImageChange.From.Namespace = cfg.Namespace
			}
			if tr.ImageChange != nil && tr.ImageChange.Tag == "" {
				tr.ImageChange.Tag = "latest"
			}

			if tr.ImageChange != nil &&
				namespace == tr.ImageChange.From.Namespace &&
				name == tr.ImageChange.From.Name &&
				tag == tr.ImageChange.Tag {

				// Either To & Tag or DockerImageReference will be used as output
				if cfg.Parameters.Output.To != nil && cfg.Parameters.Output.To.Name != "" {
					childName = cfg.Parameters.Output.To.Name
					childTag = cfg.Parameters.Output.Tag
					if cfg.Parameters.Output.To.Namespace != "" {
						childNamespace = cfg.Parameters.Output.To.Namespace
					} else {
						childNamespace = cfg.Namespace
					}
				} else {
					ref, err := imageapi.ParseDockerImageReference(cfg.Parameters.Output.DockerImageReference)
					if err != nil {
						return nil, err
					}
					childName = ref.Name
					childTag = ref.Tag
					childNamespace = cfg.Namespace
				}

				childRepo := join(childNamespace, childName)

				// Build all children and their dependency trees recursively
				child, err := findRepoDeps(childRepo, childTag, all, buildConfigList)
				if err != nil {
					return nil, err
				}

				// Add edge between root and child
				cfgFullName := join(cfg.Namespace, cfg.Name)
				root.Edges = append(root.Edges, NewEdge(cfgFullName, child.FullName))

				// If the child depends on root via more than one tag, we have to make sure
				// that only one single instance of the child will make it into root.Children
				cont := false
				for _, repo := range root.Children {
					if repo.FullName == child.FullName {
						// Just pass the tag along and discard the current child
						repo.Tags = append(repo.Tags, child.Tags...)
						cont = true
						break
					}
				}
				if cont {
					// Do not append this child in root.Children. It's already in there
					continue
				}

				root.Children = append(root.Children, child)
			}
		}
	}

	return root, nil
}

var once sync.Once

// dotDump dumps the given image repository tree in DOT syntax
func dotDump(root *ImageRepo, g *dot.Graph, graphName string) string {
	if root == nil {
		return ""
	}

	// Add current node
	rootNamespace, rootName, err := split(root.FullName)
	checkErr(err)
	attrs := make(map[string]string)
	for _, tag := range root.Tags {
		setTag(tag, attrs)
	}
	var tag string
	// Inject tag into root's name
	once.Do(func() {
		tag = root.Tags[0]
	})
	setLabel(rootName, rootNamespace, attrs, tag)
	rootName = validDOT(rootName)
	g.AddNode(graphName, rootName, attrs)

	// Add edges between current node and its children
	for _, child := range root.Children {
		for _, edge := range root.Edges {
			if child.FullName == edge.To {
				_, childName, err := split(child.FullName)
				checkErr(err)
				childName = validDOT(childName)
				edgeNamespace, edgeName, err := split(edge.FullName)
				checkErr(err)
				edgeName = validDOT(edgeName)

				edgeAttrs := make(map[string]string)
				setLabel(edgeName, edgeNamespace, edgeAttrs, "")
				g.AddEdge(rootName, childName, true, edgeAttrs)
			}
		}
		// Recursively add every child and their children as nodes
		dotDump(child, g, graphName)
	}

	dotOutput := g.String()

	// Parse DOT output for validation
	if _, err := dot.Parse([]byte(dotOutput)); err != nil {
		checkErr(fmt.Errorf("cannot parse DOT output: %v\n", err))
	}

	return dotOutput
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"koding/kites/kloud/cleaners/lookup"
)

type MultipleVMs struct {
	Cleaner       *Cleaner
	IsPaid        func(username string) bool
	UsersMultiple map[string][]lookup.MachineDocument
	Instances     lookup.MultiInstances

	multipleInstances lookup.MultiInstances
	err               error
}

func (m *MultipleVMs) Process() {
	instances := m.Instances.
		States("running").
		WithTag("koding-env", "production")

	freeUsersWithMultipleVMs := make(map[string][]lookup.MachineDocument, 0)
	for user, machines := range m.UsersMultiple {
		// if not paid user, add it to the map
		if !m.IsPaid(user) {
			freeUsersWithMultipleVMs[user] = machines
		}
	}

	datas := make([]*StopData, 0)
	ids := make([]string, 0)

	for username, machines := range freeUsersWithMultipleVMs {
		for _, machine := range machines {

			// there is no way this can panic because we fetch documents which
			// have instanceIds in it
			instanceId := machine.Meta["instanceId"].(string)

			// only add if there is an instanceId
			data := &StopData{
				id:         machine.Id,
				instanceId: instanceId,
				domain:     machine.Domain,
				ipAddress:  machine.IpAddress,
				username:   username,
				reason:     "Free user has more than two machines.",
			}

			ids = append(ids, instanceId)
			datas = append(datas, data)
		}
	}

	m.multipleInstances = instances.Only(ids...)
	if m.multipleInstances.Total() == 0 {
		return
	}

	// first stop all machines, this is a batch API call so it's more efficient
	m.multipleInstances.StopAll()

	for _, data := range datas {
		m.Cleaner.StopMachine(data)
	}
}

func (m *MultipleVMs) Result() string {
	if m.err != nil {
		return fmt.Sprintf("multipleVMs: error '%s'", m.err.Error())
	}

	return fmt.Sprintf("multipleVMs: stopped '%d' machines",
		m.multipleInstances.Total())
}
<commit_msg>cleaner: remove whitespace<commit_after>package main

import (
	"fmt"
	"koding/kites/kloud/cleaners/lookup"
)

type MultipleVMs struct {
	Cleaner       *Cleaner
	IsPaid        func(username string) bool
	UsersMultiple map[string][]lookup.MachineDocument
	Instances     lookup.MultiInstances

	multipleInstances lookup.MultiInstances
	err               error
}

func (m *MultipleVMs) Process() {
	instances := m.Instances.
		States("running").
		WithTag("koding-env", "production")

	freeUsersWithMultipleVMs := make(map[string][]lookup.MachineDocument, 0)
	for user, machines := range m.UsersMultiple {
		// if not paid user, add it to the map
		if !m.IsPaid(user) {
			freeUsersWithMultipleVMs[user] = machines
		}
	}

	datas := make([]*StopData, 0)
	ids := make([]string, 0)

	for username, machines := range freeUsersWithMultipleVMs {
		for _, machine := range machines {
			// there is no way this can panic because we fetch documents which
			// have instanceIds in it
			instanceId := machine.Meta["instanceId"].(string)

			// only add if there is an instanceId
			data := &StopData{
				id:         machine.Id,
				instanceId: instanceId,
				domain:     machine.Domain,
				ipAddress:  machine.IpAddress,
				username:   username,
				reason:     "Free user has more than two machines.",
			}

			ids = append(ids, instanceId)
			datas = append(datas, data)
		}
	}

	m.multipleInstances = instances.Only(ids...)
	if m.multipleInstances.Total() == 0 {
		return
	}

	// first stop all machines, this is a batch API call so it's more efficient
	m.multipleInstances.StopAll()

	for _, data := range datas {
		m.Cleaner.StopMachine(data)
	}
}

func (m *MultipleVMs) Result() string {
	if m.err != nil {
		return fmt.Sprintf("multipleVMs: error '%s'", m.err.Error())
	}

	return fmt.Sprintf("multipleVMs: stopped '%d' machines",
		m.multipleInstances.Total())
}
<|endoftext|>


<commit_before>package misc

// Enable or disable terminal echo.
func SetTermEcho(echo bool) {
	term := &syscall.Termios{}
	stdout := os.Stdout.Fd()
	_, _, err := syscall.Syscall(syscall.SYS_IOCTL, stdout, syscall.TCGETS, uintptr(unsafe.Pointer(term)))
	if err != 0 {
		logger.Warning("SetTermEcho", "", err, "syscall failed")
		return
	}
	if echo {
		term.Lflag |= syscall.ECHO
	} else {
		term.Lflag &^= syscall.ECHO
	}
	_, _, err = syscall.Syscall(syscall.SYS_IOCTL, stdout, uintptr(syscall.TCSETS), uintptr(unsafe.Pointer(term)))
	if err != 0 {
		logger.Warning("SetTermEcho", "", err, "syscall failed")
		return
	}
}
<commit_msg>fix missing import in sys_linux<commit_after>package misc

import (
	"os"
	"syscall"
	"unsafe"
)

// Enable or disable terminal echo.
func SetTermEcho(echo bool) {
	term := &syscall.Termios{}
	stdout := os.Stdout.Fd()
	_, _, err := syscall.Syscall(syscall.SYS_IOCTL, stdout, syscall.TCGETS, uintptr(unsafe.Pointer(term)))
	if err != 0 {
		logger.Warning("SetTermEcho", "", err, "syscall failed")
		return
	}
	if echo {
		term.Lflag |= syscall.ECHO
	} else {
		term.Lflag &^= syscall.ECHO
	}
	_, _, err = syscall.Syscall(syscall.SYS_IOCTL, stdout, uintptr(syscall.TCSETS), uintptr(unsafe.Pointer(term)))
	if err != 0 {
		logger.Warning("SetTermEcho", "", err, "syscall failed")
		return
	}
}
<|endoftext|>


<commit_before>package conf

import (
	"strings"
	"time"
)

const (
	AppName = "jiacrontab"
	Version = "v1.4-beta.1"
)

var AppService *App

type App struct {
	Debug           bool      `json:"debug"`
	HttpListenAddr  string    `json:"http_listen_addr"`
	StaticDir       string    `json:"static_dir"`
	DataFile        string    `json:"data_file"`
	RpcListenAddr   string    `json:"rpc_listen_addr"`
	ServerStartTime time.Time `json:"-"`
	TplDir          string    `json:"tpl_dir"`
	TplExt          string    `json:"tpl_ext"`

	User          string   `json:"user"`
	Passwd        string   `json:"-"`
	AllowCommands []string `json:"allow_commands"`
}

func LoadAppService() {
	app := cf.Section("app")
	AppService = &App{
		Debug:           app.Key("debug").MustBool(false),
		HttpListenAddr:  app.Key("http_listen_addr").MustString("0.0.0.0:20000"),
		StaticDir:       app.Key("static_dir").MustString("/static"),
		TplExt:          ".html",
		TplDir:          "template",
		DataFile:        app.Key("data_file").MustString("data.json"),
		RpcListenAddr:   app.Key("listen").MustString(":20003"),
		User:            app.Key("app_user").MustString("admin"),
		Passwd:          app.Key("app_passwd").MustString("123456"),
		ServerStartTime: time.Now(),
		AllowCommands:   strings.Split(app.Key("allow_commands").MustString("php,python,node,curl,wget,lua"), ","),
	}
}
<commit_msg>1.4.0<commit_after>package conf

import (
	"strings"
	"time"
)

const (
	AppName = "jiacrontab"
	Version = "v1.4.0"
)

var AppService *App

type App struct {
	Debug           bool      `json:"debug"`
	HttpListenAddr  string    `json:"http_listen_addr"`
	StaticDir       string    `json:"static_dir"`
	DataFile        string    `json:"data_file"`
	RpcListenAddr   string    `json:"rpc_listen_addr"`
	ServerStartTime time.Time `json:"-"`
	TplDir          string    `json:"tpl_dir"`
	TplExt          string    `json:"tpl_ext"`

	User          string   `json:"user"`
	Passwd        string   `json:"-"`
	AllowCommands []string `json:"allow_commands"`
}

func LoadAppService() {
	app := cf.Section("app")
	AppService = &App{
		Debug:           app.Key("debug").MustBool(false),
		HttpListenAddr:  app.Key("http_listen_addr").MustString("0.0.0.0:20000"),
		StaticDir:       app.Key("static_dir").MustString("/static"),
		TplExt:          ".html",
		TplDir:          "template",
		DataFile:        app.Key("data_file").MustString("data.json"),
		RpcListenAddr:   app.Key("listen").MustString(":20003"),
		User:            app.Key("app_user").MustString("admin"),
		Passwd:          app.Key("app_passwd").MustString("123456"),
		ServerStartTime: time.Now(),
		AllowCommands:   strings.Split(app.Key("allow_commands").MustString("php,python,node,curl,wget,lua"), ","),
	}
}
<|endoftext|>


<commit_before>package server

import (
	"fmt"
	"runtime"

	log "github.com/cihub/seelog"
	terrors "github.com/mondough/typhon/errors"
	tmsg "github.com/mondough/typhon/message"

	"github.com/mondough/mercury"
	"github.com/mondough/mercury/marshaling"
)

type Handler func(req mercury.Request) (mercury.Response, error)

// An Endpoint represents a handler function bound to a particular endpoint name.
type Endpoint struct {
	// Name is the Endpoint's unique name, and is used to route requests to it.
	Name string
	// Handler is a function to be invoked upon receiving a request, to generate a response.
	Handler Handler
	// Request is a "template" object for the Endpoint's request format.
	Request interface{}
	// Response is a "template" object for the Endpoint's response format.
	Response interface{}
}

func (e Endpoint) unmarshaler(req mercury.Request) tmsg.Unmarshaler {
	return marshaling.Unmarshaler(req.Headers()[marshaling.ContentTypeHeader], e.Request)
}

// Handle takes an inbound Request, unmarshals it, dispatches it to the handler, and serialises the result as a
// Response. Note that the response may be nil.
func (e Endpoint) Handle(req mercury.Request) (rsp mercury.Response, err error) {
	// Unmarshal the request body (unless there already is one)
	if req.Body() == nil && e.Request != nil {
		if um := e.unmarshaler(req); um != nil {
			if werr := terrors.Wrap(um.UnmarshalPayload(req), nil); werr != nil {
				log.Warnf("[Mercury:Server] Cannot unmarshal request payload: %v", werr)
				terr := werr.(*terrors.Error)
				terr.Code = terrors.ErrBadRequest
				rsp, err = nil, terr
				return
			}
		}
	}

	defer func() {
		if v := recover(); v != nil {
			traceVerbose := make([]byte, 1024)
			runtime.Stack(traceVerbose, true)
			log.Criticalf("[Mercury:Server] Recovered from handler panic for request %s:\n%v\n%s", req.Id(), v,
				string(traceVerbose))
			rsp, err = nil, terrors.InternalService("panic", fmt.Sprintf("Panic in handler %s:\n%s", req.Endpoint(),
				string(traceVerbose)))
		}
	}()
	rsp, err = e.Handler(req)
	return
}
<commit_msg>Right number of params<commit_after>package server

import (
	"fmt"
	"runtime"

	log "github.com/cihub/seelog"
	terrors "github.com/mondough/typhon/errors"
	tmsg "github.com/mondough/typhon/message"

	"github.com/mondough/mercury"
	"github.com/mondough/mercury/marshaling"
)

type Handler func(req mercury.Request) (mercury.Response, error)

// An Endpoint represents a handler function bound to a particular endpoint name.
type Endpoint struct {
	// Name is the Endpoint's unique name, and is used to route requests to it.
	Name string
	// Handler is a function to be invoked upon receiving a request, to generate a response.
	Handler Handler
	// Request is a "template" object for the Endpoint's request format.
	Request interface{}
	// Response is a "template" object for the Endpoint's response format.
	Response interface{}
}

func (e Endpoint) unmarshaler(req mercury.Request) tmsg.Unmarshaler {
	return marshaling.Unmarshaler(req.Headers()[marshaling.ContentTypeHeader], e.Request)
}

// Handle takes an inbound Request, unmarshals it, dispatches it to the handler, and serialises the result as a
// Response. Note that the response may be nil.
func (e Endpoint) Handle(req mercury.Request) (rsp mercury.Response, err error) {
	// Unmarshal the request body (unless there already is one)
	if req.Body() == nil && e.Request != nil {
		if um := e.unmarshaler(req); um != nil {
			if werr := terrors.Wrap(um.UnmarshalPayload(req), nil); werr != nil {
				log.Warnf("[Mercury:Server] Cannot unmarshal request payload: %v", werr)
				terr := werr.(*terrors.Error)
				terr.Code = terrors.ErrBadRequest
				rsp, err = nil, terr
				return
			}
		}
	}

	defer func() {
		if v := recover(); v != nil {
			traceVerbose := make([]byte, 1024)
			runtime.Stack(traceVerbose, true)
			log.Criticalf("[Mercury:Server] Recovered from handler panic for request %s:\n%v\n%s", req.Id(), v,
				string(traceVerbose))
			rsp, err = nil, terrors.InternalService("panic", fmt.Sprintf("Panic in handler %s:\n%s", req.Endpoint(),
				string(traceVerbose)), nil)
		}
	}()
	rsp, err = e.Handler(req)
	return
}
<|endoftext|>


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

package server

import (
	"fmt"
	"github.com/osrg/gobgp/config"
	"github.com/osrg/gobgp/packet"
	"github.com/stretchr/testify/assert"
	"net"
	"strconv"
	"testing"
	"time"
)

type MockConnection struct {
	net.Conn
	recvCh    chan []byte
	sendBuf   [][]byte
	readBytes int
}

func NewMockConnection() *MockConnection {
	m := &MockConnection{
		recvCh:  make(chan []byte, 128),
		sendBuf: make([][]byte, 129),
	}
	return m
}

func (m *MockConnection) Read(buf []byte) (int, error) {

	data := <-m.recvCh

	for _, val := range data {
		buf[m.readBytes] = val
		m.readBytes += 1
	}

	length := 0
	if m.readBytes == len(buf) {
		m.readBytes = 0
		length = len(buf)
	} else {
		length = m.readBytes
	}

	fmt.Printf("%d bytes read from peer\n", length)
	return length, nil
}

func (m *MockConnection) Write(buf []byte) (int, error) {
	m.sendBuf = append(m.sendBuf, buf)
	msg, _ := bgp.ParseBGPMessage(buf)
	fmt.Printf("%d bytes written by gobgp  message type : %s\n", len(buf), showMessageType(msg.Header.Type))
	return len(buf), nil
}

func showMessageType(t uint8) string {
	switch t {
	case bgp.BGP_MSG_KEEPALIVE:
		return "BGP_MSG_KEEPALIVE"
	case bgp.BGP_MSG_NOTIFICATION:
		return "BGP_MSG_NOTIFICATION"
	case bgp.BGP_MSG_OPEN:
		return "BGP_MSG_OPEN"
	case bgp.BGP_MSG_UPDATE:
		return "BGP_MSG_UPDATE"
	case bgp.BGP_MSG_ROUTE_REFRESH:
		return "BGP_MSG_ROUTE_REFRESH"
	}
	return strconv.Itoa(int(t))
}

func (m *MockConnection) Close() error {
	fmt.Printf("close called")
	return nil
}

func TestReadAll(t *testing.T) {
	assert := assert.New(t)
	m := NewMockConnection()
	msg := open()
	expected1, _ := msg.Header.Serialize()
	expected2, _ := msg.Body.Serialize()

	pushBytes := func() {
		fmt.Println("push 5 bytes")
		m.recvCh <- expected1[0:5]
		fmt.Println("wait 5 seconds...")
		time.Sleep(time.Second * 5)
		fmt.Println("push rest")
		m.recvCh <- expected1[5:]
		fmt.Println("push bytes at once")
		m.recvCh <- expected2
	}

	go pushBytes()

	var actual1 []byte
	actual1, _ = readAll(m, bgp.BGP_HEADER_LENGTH)
	fmt.Println(actual1)
	assert.Equal(expected1, actual1)

	var actual2 []byte
	actual2, _ = readAll(m, len(expected2))
	fmt.Println(actual2)
	assert.Equal(expected2, actual2)
}

func TestFSMHandlerEstablish_HoldTimerExpired(t *testing.T) {
	assert := assert.New(t)
	m := NewMockConnection()

	p, h := makePeerAndHandler()

	// push mock connection
	p.fsm.passiveConn = m

	// set up keepalive ticker
	sec := time.Second * 2
	p.fsm.keepaliveTicker = time.NewTicker(sec)

	msg := keepalive()
	header, _ := msg.Header.Serialize()
	body, _ := msg.Body.Serialize()

	pushPackets := func() {
		// first keepalive from peer
		m.recvCh <- header
		m.recvCh <- body
		time.Sleep(time.Second * 4)
		// second keepalive from peer
		m.recvCh <- header
		m.recvCh <- body
	}

	// set holdtime
	p.fsm.peerConfig.Timers.HoldTime = 10
	p.fsm.negotiatedHoldTime = 10

	go pushPackets()
	state := h.established()
	time.Sleep(time.Second * 4)
	assert.Equal(bgp.BGP_FSM_IDLE, state)
	lastMsg := m.sendBuf[len(m.sendBuf)-1]
	sent, _ := bgp.ParseBGPMessage(lastMsg)
	assert.Equal(bgp.BGP_MSG_NOTIFICATION, sent.Header.Type)
	assert.Equal(bgp.BGP_ERROR_HOLD_TIMER_EXPIRED, sent.Body.(*bgp.BGPNotification).ErrorCode)
}

func makePeerAndHandler() (*Peer, *FSMHandler) {
	globalConfig := config.GlobalType{}
	neighborConfig := config.NeighborType{}

	p := &Peer{
		globalConfig:   globalConfig,
		peerConfig:     neighborConfig,
		acceptedConnCh: make(chan net.Conn),
		serverMsgCh:    make(chan *serverMsg),
		peerMsgCh:      make(chan *peerMsg),
		capMap:         make(map[bgp.BGPCapabilityCode]bgp.ParameterCapabilityInterface),
	}

	p.siblings = make(map[string]*serverMsgDataPeer)
	p.fsm = NewFSM(&globalConfig, &neighborConfig, p.acceptedConnCh)

	incoming := make(chan *fsmMsg, FSM_CHANNEL_LENGTH)
	p.outgoing = make(chan *bgp.BGPMessage, FSM_CHANNEL_LENGTH)

	h := &FSMHandler{
		fsm:      p.fsm,
		errorCh:  make(chan bool, 2),
		incoming: incoming,
		outgoing: p.outgoing,
	}

	return p, h

}

func open() *bgp.BGPMessage {
	p1 := bgp.NewOptionParameterCapability(
		[]bgp.ParameterCapabilityInterface{bgp.NewCapRouteRefresh()})
	p2 := bgp.NewOptionParameterCapability(
		[]bgp.ParameterCapabilityInterface{bgp.NewCapMultiProtocol(3, 4)})
	g := bgp.CapGracefulRestartTuples{4, 2, 3}
	p3 := bgp.NewOptionParameterCapability(
		[]bgp.ParameterCapabilityInterface{bgp.NewCapGracefulRestart(2, 100,
			[]bgp.CapGracefulRestartTuples{g})})
	p4 := bgp.NewOptionParameterCapability(
		[]bgp.ParameterCapabilityInterface{bgp.NewCapFourOctetASNumber(100000)})
	return bgp.NewBGPOpenMessage(11033, 303, "100.4.10.3",
		[]bgp.OptionParameterInterface{p1, p2, p3, p4})
}

func keepalive() *bgp.BGPMessage {
	return bgp.NewBGPKeepAliveMessage()
}
<commit_msg>fsm: add OpenSent and OpenConfirm testcases<commit_after>// Copyright (C) 2014 Nippon Telegraph and Telephone Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package server

import (
	"fmt"
	"github.com/osrg/gobgp/config"
	"github.com/osrg/gobgp/packet"
	"github.com/stretchr/testify/assert"
	"net"
	"strconv"
	"testing"
	"time"
)

type MockConnection struct {
	net.Conn
	recvCh    chan []byte
	sendBuf   [][]byte
	readBytes int
}

func NewMockConnection() *MockConnection {
	m := &MockConnection{
		recvCh:  make(chan []byte, 128),
		sendBuf: make([][]byte, 129),
	}
	return m
}

func (m *MockConnection) Read(buf []byte) (int, error) {

	data := <-m.recvCh
	rest := len(buf) - m.readBytes
	if len(data) > rest {
		m.recvCh <- data[rest:]
		data = data[:rest]
	}

	for _, val := range data {
		buf[m.readBytes] = val
		m.readBytes += 1
	}

	length := 0
	if m.readBytes == len(buf) {
		m.readBytes = 0
		length = len(buf)
	} else {
		length = m.readBytes
	}

	fmt.Printf("%d bytes read from peer\n", length)
	return length, nil
}

func (m *MockConnection) Write(buf []byte) (int, error) {
	m.sendBuf = append(m.sendBuf, buf)
	msg, _ := bgp.ParseBGPMessage(buf)
	fmt.Printf("%d bytes written by gobgp  message type : %s\n", len(buf), showMessageType(msg.Header.Type))
	return len(buf), nil
}

func showMessageType(t uint8) string {
	switch t {
	case bgp.BGP_MSG_KEEPALIVE:
		return "BGP_MSG_KEEPALIVE"
	case bgp.BGP_MSG_NOTIFICATION:
		return "BGP_MSG_NOTIFICATION"
	case bgp.BGP_MSG_OPEN:
		return "BGP_MSG_OPEN"
	case bgp.BGP_MSG_UPDATE:
		return "BGP_MSG_UPDATE"
	case bgp.BGP_MSG_ROUTE_REFRESH:
		return "BGP_MSG_ROUTE_REFRESH"
	}
	return strconv.Itoa(int(t))
}

func (m *MockConnection) Close() error {
	fmt.Printf("close called\n")
	return nil
}

func TestReadAll(t *testing.T) {
	assert := assert.New(t)
	m := NewMockConnection()
	msg := open()
	expected1, _ := msg.Header.Serialize()
	expected2, _ := msg.Body.Serialize()

	pushBytes := func() {
		fmt.Println("push 5 bytes")
		m.recvCh <- expected1[0:5]
		fmt.Println("wait 5 seconds...")
		time.Sleep(time.Second * 5)
		fmt.Println("push rest")
		m.recvCh <- expected1[5:]
		fmt.Println("push bytes at once")
		m.recvCh <- expected2
	}

	go pushBytes()

	var actual1 []byte
	actual1, _ = readAll(m, bgp.BGP_HEADER_LENGTH)
	fmt.Println(actual1)
	assert.Equal(expected1, actual1)

	var actual2 []byte
	actual2, _ = readAll(m, len(expected2))
	fmt.Println(actual2)
	assert.Equal(expected2, actual2)
}

func TestFSMHandlerOpensent_HoldTimerExpired(t *testing.T) {
	assert := assert.New(t)
	m := NewMockConnection()

	p, h := makePeerAndHandler()

	// push mock connection
	p.fsm.passiveConn = m

	// set up keepalive ticker
	sec := time.Second * 2
	p.fsm.keepaliveTicker = time.NewTicker(sec)

	// set holdtime
	p.fsm.opensentHoldTime = 5

	state := h.opensent()

	assert.Equal(bgp.BGP_FSM_IDLE, state)
	lastMsg := m.sendBuf[len(m.sendBuf)-1]
	sent, _ := bgp.ParseBGPMessage(lastMsg)
	assert.Equal(bgp.BGP_MSG_NOTIFICATION, sent.Header.Type)
	assert.Equal(bgp.BGP_ERROR_HOLD_TIMER_EXPIRED, sent.Body.(*bgp.BGPNotification).ErrorCode)

}

func TestFSMHandlerOpenconfirm_HoldTimerExpired(t *testing.T) {
	assert := assert.New(t)
	m := NewMockConnection()

	p, h := makePeerAndHandler()

	// push mock connection
	p.fsm.passiveConn = m

	// set up keepalive ticker
	p.fsm.peerConfig.Timers.KeepaliveInterval = 2

	// set holdtime
	p.fsm.negotiatedHoldTime = 10
	state := h.openconfirm()

	assert.Equal(bgp.BGP_FSM_IDLE, state)
	lastMsg := m.sendBuf[len(m.sendBuf)-1]
	sent, _ := bgp.ParseBGPMessage(lastMsg)
	assert.Equal(bgp.BGP_MSG_NOTIFICATION, sent.Header.Type)
	assert.Equal(bgp.BGP_ERROR_HOLD_TIMER_EXPIRED, sent.Body.(*bgp.BGPNotification).ErrorCode)

}

func TestFSMHandlerEstablish_HoldTimerExpired(t *testing.T) {
	assert := assert.New(t)
	m := NewMockConnection()

	p, h := makePeerAndHandler()

	// push mock connection
	p.fsm.passiveConn = m

	// set up keepalive ticker
	sec := time.Second * 2
	p.fsm.keepaliveTicker = time.NewTicker(sec)

	msg := keepalive()
	header, _ := msg.Header.Serialize()
	body, _ := msg.Body.Serialize()

	pushPackets := func() {
		// first keepalive from peer
		m.recvCh <- header
		m.recvCh <- body
	}

	// set holdtime
	p.fsm.peerConfig.Timers.HoldTime = 10
	p.fsm.negotiatedHoldTime = 10

	go pushPackets()
	state := h.established()
	time.Sleep(time.Second * 4)
	assert.Equal(bgp.BGP_FSM_IDLE, state)
	lastMsg := m.sendBuf[len(m.sendBuf)-1]
	sent, _ := bgp.ParseBGPMessage(lastMsg)
	assert.Equal(bgp.BGP_MSG_NOTIFICATION, sent.Header.Type)
	assert.Equal(bgp.BGP_ERROR_HOLD_TIMER_EXPIRED, sent.Body.(*bgp.BGPNotification).ErrorCode)
}

func makePeerAndHandler() (*Peer, *FSMHandler) {
	globalConfig := config.GlobalType{}
	neighborConfig := config.NeighborType{}

	p := &Peer{
		globalConfig:   globalConfig,
		peerConfig:     neighborConfig,
		acceptedConnCh: make(chan net.Conn),
		serverMsgCh:    make(chan *serverMsg),
		peerMsgCh:      make(chan *peerMsg),
		capMap:         make(map[bgp.BGPCapabilityCode]bgp.ParameterCapabilityInterface),
	}

	p.siblings = make(map[string]*serverMsgDataPeer)
	p.fsm = NewFSM(&globalConfig, &neighborConfig, p.acceptedConnCh)

	incoming := make(chan *fsmMsg, FSM_CHANNEL_LENGTH)
	p.outgoing = make(chan *bgp.BGPMessage, FSM_CHANNEL_LENGTH)

	h := &FSMHandler{
		fsm:      p.fsm,
		errorCh:  make(chan bool, 2),
		incoming: incoming,
		outgoing: p.outgoing,
	}

	return p, h

}

func open() *bgp.BGPMessage {
	p1 := bgp.NewOptionParameterCapability(
		[]bgp.ParameterCapabilityInterface{bgp.NewCapRouteRefresh()})
	p2 := bgp.NewOptionParameterCapability(
		[]bgp.ParameterCapabilityInterface{bgp.NewCapMultiProtocol(3, 4)})
	g := bgp.CapGracefulRestartTuples{4, 2, 3}
	p3 := bgp.NewOptionParameterCapability(
		[]bgp.ParameterCapabilityInterface{bgp.NewCapGracefulRestart(2, 100,
			[]bgp.CapGracefulRestartTuples{g})})
	p4 := bgp.NewOptionParameterCapability(
		[]bgp.ParameterCapabilityInterface{bgp.NewCapFourOctetASNumber(100000)})
	return bgp.NewBGPOpenMessage(11033, 303, "100.4.10.3",
		[]bgp.OptionParameterInterface{p1, p2, p3, p4})
}

func keepalive() *bgp.BGPMessage {
	return bgp.NewBGPKeepAliveMessage()
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"net/http"
	"strings"
	"time"

	"github.com/gorilla/websocket"

	"buildblast/server/lib/game"
	"buildblast/server/lib/proto"
	"buildblast/shared/db"
	"buildblast/shared/util"
)

var globalGame *Game

var upgrader = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
	CheckOrigin: func(r *http.Request) bool {
		return true
	},
}

func handler(w http.ResponseWriter, r *http.Request, clientLoc string) {
	// Workaround for Quentin's system configuration.
	// For some reason, css files are getting served
	// without a content-type...
	if strings.HasSuffix(r.URL.Path, ".css") {
		w.Header().Set("Content-Type", "text/css")
	}
	w.Header().Add("Cache-Control", "max-age=300, public, must-revalidate, proxy-revalidate")

	http.ServeFile(w, r, clientLoc+r.URL.Path)
}

func getClientName(r *http.Request) string {
	bits := strings.Split(r.URL.Path, "/")
	if len(bits) < 4 {
		return ""
	}
	return bits[3]
}

func mainSocketHandler(w http.ResponseWriter, r *http.Request) {
	var account db.Account
	authenticated := false
	if dbc != nil {
		cj := util.NewCookieJar(w, r, config.CookieKeyPairs...)
		account, _, authenticated = cj.Authenticate(dbc)
		cj.SaveSession()
	}

	wsConn, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		fmt.Println("Couldn't upgrade websocket:", err)
	}

	conn := NewConn(wsConn)

	var baseName string
	if authenticated {
		baseName = account.Username
	} else {
		baseName = "guest"
	}

	name := baseName
	nameNumber := 1
	var client *Client
	for {
		var isNew bool
		client, isNew = globalGame.clientWithId(name)
		if isNew {
			break
		}
		name = fmt.Sprintf("%s-%d", baseName, nameNumber)
		nameNumber++
	}

	// FIXME: We could give the client their entity's
	// actual initial state as part of the handshake,
	// but it's currently impossible since the entity
	// isn't yet created at the handshake stage.
	info := makePlayerEntityCreatedMessage(game.EntityId(name), &game.BioticState{})

	conn.Send(&proto.MsgHandshakeReply{
		ServerTime:       float64(time.Now().UnixNano()) / 1e6,
		ClientId:         name,
		PlayerEntityInfo: *info,
	})

	client.Run(conn)
}

func chunkSocketHandler(w http.ResponseWriter, r *http.Request) {
	name := getClientName(r)

	wsConn, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		fmt.Println("Couldn't upgrade websocket:", err)
	}

	client, isNew := globalGame.clientWithId(name)
	if isNew {
		log.Println("Warning: Attempt to connect to chunk socket for client '" + name + "' who is not connected on main socket!")
		globalGame.Disconnect(name, "invalid connection")
		return
	}
	client.RunChunks(NewConn(wsConn))
}
<commit_msg>Log user logins.<commit_after>package main

import (
	"fmt"
	"log"
	"net/http"
	"strings"
	"time"

	"github.com/gorilla/websocket"

	"buildblast/server/lib/game"
	"buildblast/server/lib/proto"
	"buildblast/shared/db"
	"buildblast/shared/util"
)

var globalGame *Game

var upgrader = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
	CheckOrigin: func(r *http.Request) bool {
		return true
	},
}

func handler(w http.ResponseWriter, r *http.Request, clientLoc string) {
	// Workaround for Quentin's system configuration.
	// For some reason, css files are getting served
	// without a content-type...
	if strings.HasSuffix(r.URL.Path, ".css") {
		w.Header().Set("Content-Type", "text/css")
	}
	w.Header().Add("Cache-Control", "max-age=300, public, must-revalidate, proxy-revalidate")

	http.ServeFile(w, r, clientLoc+r.URL.Path)
}

func getClientName(r *http.Request) string {
	bits := strings.Split(r.URL.Path, "/")
	if len(bits) < 4 {
		return ""
	}
	return bits[3]
}

func mainSocketHandler(w http.ResponseWriter, r *http.Request) {
	var account db.Account
	authenticated := false
	if dbc != nil {
		cj := util.NewCookieJar(w, r, config.CookieKeyPairs...)
		account, _, authenticated = cj.Authenticate(dbc)
		cj.SaveSession()
		fmt.Println("Authentication: ", authenticated, "(ID: ", account.Id, ") User: "+account.Username)
	}

	wsConn, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		fmt.Println("Couldn't upgrade websocket:", err)
	}

	conn := NewConn(wsConn)

	var baseName string
	if authenticated {
		baseName = account.Username
	} else {
		baseName = "guest"
	}

	name := baseName
	nameNumber := 1
	var client *Client
	for {
		var isNew bool
		client, isNew = globalGame.clientWithId(name)
		if isNew {
			break
		}
		name = fmt.Sprintf("%s-%d", baseName, nameNumber)
		nameNumber++
	}

	// FIXME: We could give the client their entity's
	// actual initial state as part of the handshake,
	// but it's currently impossible since the entity
	// isn't yet created at the handshake stage.
	info := makePlayerEntityCreatedMessage(game.EntityId(name), &game.BioticState{})

	conn.Send(&proto.MsgHandshakeReply{
		ServerTime:       float64(time.Now().UnixNano()) / 1e6,
		ClientId:         name,
		PlayerEntityInfo: *info,
	})

	client.Run(conn)
}

func chunkSocketHandler(w http.ResponseWriter, r *http.Request) {
	name := getClientName(r)

	wsConn, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		fmt.Println("Couldn't upgrade websocket:", err)
	}

	client, isNew := globalGame.clientWithId(name)
	if isNew {
		log.Println("Warning: Attempt to connect to chunk socket for client '" + name + "' who is not connected on main socket!")
		globalGame.Disconnect(name, "invalid connection")
		return
	}
	client.RunChunks(NewConn(wsConn))
}
<|endoftext|>


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

package types2

import (
	"container/heap"
	"fmt"
)

// initOrder computes the Info.InitOrder for package variables.
func (check *Checker) initOrder() {
	// An InitOrder may already have been computed if a package is
	// built from several calls to (*Checker).Files. Clear it.
	check.Info.InitOrder = check.Info.InitOrder[:0]

	// Compute the object dependency graph and initialize
	// a priority queue with the list of graph nodes.
	pq := nodeQueue(dependencyGraph(check.objMap))
	heap.Init(&pq)

	const debug = false
	if debug {
		fmt.Printf("Computing initialization order for %s\n\n", check.pkg)
		fmt.Println("Object dependency graph:")
		for obj, d := range check.objMap {
			// only print objects that may appear in the dependency graph
			if obj, _ := obj.(dependency); obj != nil {
				if len(d.deps) > 0 {
					fmt.Printf("\t%s depends on\n", obj.Name())
					for dep := range d.deps {
						fmt.Printf("\t\t%s\n", dep.Name())
					}
				} else {
					fmt.Printf("\t%s has no dependencies\n", obj.Name())
				}
			}
		}
		fmt.Println()

		fmt.Println("Transposed object dependency graph (functions eliminated):")
		for _, n := range pq {
			fmt.Printf("\t%s depends on %d nodes\n", n.obj.Name(), n.ndeps)
			for p := range n.pred {
				fmt.Printf("\t\t%s is dependent\n", p.obj.Name())
			}
		}
		fmt.Println()

		fmt.Println("Processing nodes:")
	}

	// Determine initialization order by removing the highest priority node
	// (the one with the fewest dependencies) and its edges from the graph,
	// repeatedly, until there are no nodes left.
	// In a valid Go program, those nodes always have zero dependencies (after
	// removing all incoming dependencies), otherwise there are initialization
	// cycles.
	emitted := make(map[*declInfo]bool)
	for len(pq) > 0 {
		// get the next node
		n := heap.Pop(&pq).(*graphNode)

		if debug {
			fmt.Printf("\t%s (src pos %d) depends on %d nodes now\n",
				n.obj.Name(), n.obj.order(), n.ndeps)
		}

		// if n still depends on other nodes, we have a cycle
		if n.ndeps > 0 {
			cycle := findPath(check.objMap, n.obj, n.obj, make(map[Object]bool))
			// If n.obj is not part of the cycle (e.g., n.obj->b->c->d->c),
			// cycle will be nil. Don't report anything in that case since
			// the cycle is reported when the algorithm gets to an object
			// in the cycle.
			// Furthermore, once an object in the cycle is encountered,
			// the cycle will be broken (dependency count will be reduced
			// below), and so the remaining nodes in the cycle don't trigger
			// another error (unless they are part of multiple cycles).
			if cycle != nil {
				check.reportCycle(cycle)
			}
			// Ok to continue, but the variable initialization order
			// will be incorrect at this point since it assumes no
			// cycle errors.
		}

		// reduce dependency count of all dependent nodes
		// and update priority queue
		for p := range n.pred {
			p.ndeps--
			heap.Fix(&pq, p.index)
		}

		// record the init order for variables with initializers only
		v, _ := n.obj.(*Var)
		info := check.objMap[v]
		if v == nil || !info.hasInitializer() {
			continue
		}

		// n:1 variable declarations such as: a, b = f()
		// introduce a node for each lhs variable (here: a, b);
		// but they all have the same initializer - emit only
		// one, for the first variable seen
		if emitted[info] {
			continue // initializer already emitted, if any
		}
		emitted[info] = true

		infoLhs := info.lhs // possibly nil (see declInfo.lhs field comment)
		if infoLhs == nil {
			infoLhs = []*Var{v}
		}
		init := &Initializer{infoLhs, info.init}
		check.Info.InitOrder = append(check.Info.InitOrder, init)
	}

	if debug {
		fmt.Println()
		fmt.Println("Initialization order:")
		for _, init := range check.Info.InitOrder {
			fmt.Printf("\t%s\n", init)
		}
		fmt.Println()
	}
}

// findPath returns the (reversed) list of objects []Object{to, ... from}
// such that there is a path of object dependencies from 'from' to 'to'.
// If there is no such path, the result is nil.
func findPath(objMap map[Object]*declInfo, from, to Object, seen map[Object]bool) []Object {
	if seen[from] {
		return nil
	}
	seen[from] = true

	for d := range objMap[from].deps {
		if d == to {
			return []Object{d}
		}
		if P := findPath(objMap, d, to, seen); P != nil {
			return append(P, d)
		}
	}

	return nil
}

// reportCycle reports an error for the given cycle.
func (check *Checker) reportCycle(cycle []Object) {
	obj := cycle[0]
	check.errorf(obj, "initialization cycle for %s", obj.Name())
	// subtle loop: print cycle[i] for i = 0, n-1, n-2, ... 1 for len(cycle) = n
	for i := len(cycle) - 1; i >= 0; i-- {
		check.errorf(obj, "\t%s refers to", obj.Name()) // secondary error, \t indented
		obj = cycle[i]
	}
	// print cycle[0] again to close the cycle
	check.errorf(obj, "\t%s", obj.Name())
}

// ----------------------------------------------------------------------------
// Object dependency graph

// A dependency is an object that may be a dependency in an initialization
// expression. Only constants, variables, and functions can be dependencies.
// Constants are here because constant expression cycles are reported during
// initialization order computation.
type dependency interface {
	Object
	isDependency()
}

// A graphNode represents a node in the object dependency graph.
// Each node p in n.pred represents an edge p->n, and each node
// s in n.succ represents an edge n->s; with a->b indicating that
// a depends on b.
type graphNode struct {
	obj        dependency // object represented by this node
	pred, succ nodeSet    // consumers and dependencies of this node (lazily initialized)
	index      int        // node index in graph slice/priority queue
	ndeps      int        // number of outstanding dependencies before this object can be initialized
}

type nodeSet map[*graphNode]bool

func (s *nodeSet) add(p *graphNode) {
	if *s == nil {
		*s = make(nodeSet)
	}
	(*s)[p] = true
}

// dependencyGraph computes the object dependency graph from the given objMap,
// with any function nodes removed. The resulting graph contains only constants
// and variables.
func dependencyGraph(objMap map[Object]*declInfo) []*graphNode {
	// M is the dependency (Object) -> graphNode mapping
	M := make(map[dependency]*graphNode)
	for obj := range objMap {
		// only consider nodes that may be an initialization dependency
		if obj, _ := obj.(dependency); obj != nil {
			M[obj] = &graphNode{obj: obj}
		}
	}

	// compute edges for graph M
	// (We need to include all nodes, even isolated ones, because they still need
	// to be scheduled for initialization in correct order relative to other nodes.)
	for obj, n := range M {
		// for each dependency obj -> d (= deps[i]), create graph edges n->s and s->n
		for d := range objMap[obj].deps {
			// only consider nodes that may be an initialization dependency
			if d, _ := d.(dependency); d != nil {
				d := M[d]
				n.succ.add(d)
				d.pred.add(n)
			}
		}
	}

	// remove function nodes and collect remaining graph nodes in G
	// (Mutually recursive functions may introduce cycles among themselves
	// which are permitted. Yet such cycles may incorrectly inflate the dependency
	// count for variables which in turn may not get scheduled for initialization
	// in correct order.)
	var G []*graphNode
	for obj, n := range M {
		if _, ok := obj.(*Func); ok {
			// connect each predecessor p of n with each successor s
			// and drop the function node (don't collect it in G)
			for p := range n.pred {
				// ignore self-cycles
				if p != n {
					// Each successor s of n becomes a successor of p, and
					// each predecessor p of n becomes a predecessor of s.
					for s := range n.succ {
						// ignore self-cycles
						if s != n {
							p.succ.add(s)
							s.pred.add(p)
							delete(s.pred, n) // remove edge to n
						}
					}
					delete(p.succ, n) // remove edge to n
				}
			}
		} else {
			// collect non-function nodes
			G = append(G, n)
		}
	}

	// fill in index and ndeps fields
	for i, n := range G {
		n.index = i
		n.ndeps = len(n.succ)
	}

	return G
}

// ----------------------------------------------------------------------------
// Priority queue

// nodeQueue implements the container/heap interface;
// a nodeQueue may be used as a priority queue.
type nodeQueue []*graphNode

func (a nodeQueue) Len() int { return len(a) }

func (a nodeQueue) Swap(i, j int) {
	x, y := a[i], a[j]
	a[i], a[j] = y, x
	x.index, y.index = j, i
}

func (a nodeQueue) Less(i, j int) bool {
	x, y := a[i], a[j]
	// nodes are prioritized by number of incoming dependencies (1st key)
	// and source order (2nd key)
	return x.ndeps < y.ndeps || x.ndeps == y.ndeps && x.obj.order() < y.obj.order()
}

func (a *nodeQueue) Push(x interface{}) {
	panic("unreachable")
}

func (a *nodeQueue) Pop() interface{} {
	n := len(*a)
	x := (*a)[n-1]
	x.index = -1 // for safety
	*a = (*a)[:n-1]
	return x
}
<commit_msg>[dev.typeparams] cmd/compile/internal/types2: review of initorder.go<commit_after>// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package types2

import (
	"container/heap"
	"fmt"
)

// initOrder computes the Info.InitOrder for package variables.
func (check *Checker) initOrder() {
	// An InitOrder may already have been computed if a package is
	// built from several calls to (*Checker).Files. Clear it.
	check.Info.InitOrder = check.Info.InitOrder[:0]

	// Compute the object dependency graph and initialize
	// a priority queue with the list of graph nodes.
	pq := nodeQueue(dependencyGraph(check.objMap))
	heap.Init(&pq)

	const debug = false
	if debug {
		fmt.Printf("Computing initialization order for %s\n\n", check.pkg)
		fmt.Println("Object dependency graph:")
		for obj, d := range check.objMap {
			// only print objects that may appear in the dependency graph
			if obj, _ := obj.(dependency); obj != nil {
				if len(d.deps) > 0 {
					fmt.Printf("\t%s depends on\n", obj.Name())
					for dep := range d.deps {
						fmt.Printf("\t\t%s\n", dep.Name())
					}
				} else {
					fmt.Printf("\t%s has no dependencies\n", obj.Name())
				}
			}
		}
		fmt.Println()

		fmt.Println("Transposed object dependency graph (functions eliminated):")
		for _, n := range pq {
			fmt.Printf("\t%s depends on %d nodes\n", n.obj.Name(), n.ndeps)
			for p := range n.pred {
				fmt.Printf("\t\t%s is dependent\n", p.obj.Name())
			}
		}
		fmt.Println()

		fmt.Println("Processing nodes:")
	}

	// Determine initialization order by removing the highest priority node
	// (the one with the fewest dependencies) and its edges from the graph,
	// repeatedly, until there are no nodes left.
	// In a valid Go program, those nodes always have zero dependencies (after
	// removing all incoming dependencies), otherwise there are initialization
	// cycles.
	emitted := make(map[*declInfo]bool)
	for len(pq) > 0 {
		// get the next node
		n := heap.Pop(&pq).(*graphNode)

		if debug {
			fmt.Printf("\t%s (src pos %d) depends on %d nodes now\n",
				n.obj.Name(), n.obj.order(), n.ndeps)
		}

		// if n still depends on other nodes, we have a cycle
		if n.ndeps > 0 {
			cycle := findPath(check.objMap, n.obj, n.obj, make(map[Object]bool))
			// If n.obj is not part of the cycle (e.g., n.obj->b->c->d->c),
			// cycle will be nil. Don't report anything in that case since
			// the cycle is reported when the algorithm gets to an object
			// in the cycle.
			// Furthermore, once an object in the cycle is encountered,
			// the cycle will be broken (dependency count will be reduced
			// below), and so the remaining nodes in the cycle don't trigger
			// another error (unless they are part of multiple cycles).
			if cycle != nil {
				check.reportCycle(cycle)
			}
			// Ok to continue, but the variable initialization order
			// will be incorrect at this point since it assumes no
			// cycle errors.
		}

		// reduce dependency count of all dependent nodes
		// and update priority queue
		for p := range n.pred {
			p.ndeps--
			heap.Fix(&pq, p.index)
		}

		// record the init order for variables with initializers only
		v, _ := n.obj.(*Var)
		info := check.objMap[v]
		if v == nil || !info.hasInitializer() {
			continue
		}

		// n:1 variable declarations such as: a, b = f()
		// introduce a node for each lhs variable (here: a, b);
		// but they all have the same initializer - emit only
		// one, for the first variable seen
		if emitted[info] {
			continue // initializer already emitted, if any
		}
		emitted[info] = true

		infoLhs := info.lhs // possibly nil (see declInfo.lhs field comment)
		if infoLhs == nil {
			infoLhs = []*Var{v}
		}
		init := &Initializer{infoLhs, info.init}
		check.Info.InitOrder = append(check.Info.InitOrder, init)
	}

	if debug {
		fmt.Println()
		fmt.Println("Initialization order:")
		for _, init := range check.Info.InitOrder {
			fmt.Printf("\t%s\n", init)
		}
		fmt.Println()
	}
}

// findPath returns the (reversed) list of objects []Object{to, ... from}
// such that there is a path of object dependencies from 'from' to 'to'.
// If there is no such path, the result is nil.
func findPath(objMap map[Object]*declInfo, from, to Object, seen map[Object]bool) []Object {
	if seen[from] {
		return nil
	}
	seen[from] = true

	for d := range objMap[from].deps {
		if d == to {
			return []Object{d}
		}
		if P := findPath(objMap, d, to, seen); P != nil {
			return append(P, d)
		}
	}

	return nil
}

// reportCycle reports an error for the given cycle.
func (check *Checker) reportCycle(cycle []Object) {
	obj := cycle[0]
	check.errorf(obj, "initialization cycle for %s", obj.Name())
	// subtle loop: print cycle[i] for i = 0, n-1, n-2, ... 1 for len(cycle) = n
	for i := len(cycle) - 1; i >= 0; i-- {
		check.errorf(obj, "\t%s refers to", obj.Name()) // secondary error, \t indented
		obj = cycle[i]
	}
	// print cycle[0] again to close the cycle
	check.errorf(obj, "\t%s", obj.Name())
}

// ----------------------------------------------------------------------------
// Object dependency graph

// A dependency is an object that may be a dependency in an initialization
// expression. Only constants, variables, and functions can be dependencies.
// Constants are here because constant expression cycles are reported during
// initialization order computation.
type dependency interface {
	Object
	isDependency()
}

// A graphNode represents a node in the object dependency graph.
// Each node p in n.pred represents an edge p->n, and each node
// s in n.succ represents an edge n->s; with a->b indicating that
// a depends on b.
type graphNode struct {
	obj        dependency // object represented by this node
	pred, succ nodeSet    // consumers and dependencies of this node (lazily initialized)
	index      int        // node index in graph slice/priority queue
	ndeps      int        // number of outstanding dependencies before this object can be initialized
}

type nodeSet map[*graphNode]bool

func (s *nodeSet) add(p *graphNode) {
	if *s == nil {
		*s = make(nodeSet)
	}
	(*s)[p] = true
}

// dependencyGraph computes the object dependency graph from the given objMap,
// with any function nodes removed. The resulting graph contains only constants
// and variables.
func dependencyGraph(objMap map[Object]*declInfo) []*graphNode {
	// M is the dependency (Object) -> graphNode mapping
	M := make(map[dependency]*graphNode)
	for obj := range objMap {
		// only consider nodes that may be an initialization dependency
		if obj, _ := obj.(dependency); obj != nil {
			M[obj] = &graphNode{obj: obj}
		}
	}

	// compute edges for graph M
	// (We need to include all nodes, even isolated ones, because they still need
	// to be scheduled for initialization in correct order relative to other nodes.)
	for obj, n := range M {
		// for each dependency obj -> d (= deps[i]), create graph edges n->s and s->n
		for d := range objMap[obj].deps {
			// only consider nodes that may be an initialization dependency
			if d, _ := d.(dependency); d != nil {
				d := M[d]
				n.succ.add(d)
				d.pred.add(n)
			}
		}
	}

	// remove function nodes and collect remaining graph nodes in G
	// (Mutually recursive functions may introduce cycles among themselves
	// which are permitted. Yet such cycles may incorrectly inflate the dependency
	// count for variables which in turn may not get scheduled for initialization
	// in correct order.)
	var G []*graphNode
	for obj, n := range M {
		if _, ok := obj.(*Func); ok {
			// connect each predecessor p of n with each successor s
			// and drop the function node (don't collect it in G)
			for p := range n.pred {
				// ignore self-cycles
				if p != n {
					// Each successor s of n becomes a successor of p, and
					// each predecessor p of n becomes a predecessor of s.
					for s := range n.succ {
						// ignore self-cycles
						if s != n {
							p.succ.add(s)
							s.pred.add(p)
							delete(s.pred, n) // remove edge to n
						}
					}
					delete(p.succ, n) // remove edge to n
				}
			}
		} else {
			// collect non-function nodes
			G = append(G, n)
		}
	}

	// fill in index and ndeps fields
	for i, n := range G {
		n.index = i
		n.ndeps = len(n.succ)
	}

	return G
}

// ----------------------------------------------------------------------------
// Priority queue

// nodeQueue implements the container/heap interface;
// a nodeQueue may be used as a priority queue.
type nodeQueue []*graphNode

func (a nodeQueue) Len() int { return len(a) }

func (a nodeQueue) Swap(i, j int) {
	x, y := a[i], a[j]
	a[i], a[j] = y, x
	x.index, y.index = j, i
}

func (a nodeQueue) Less(i, j int) bool {
	x, y := a[i], a[j]
	// nodes are prioritized by number of incoming dependencies (1st key)
	// and source order (2nd key)
	return x.ndeps < y.ndeps || x.ndeps == y.ndeps && x.obj.order() < y.obj.order()
}

func (a *nodeQueue) Push(x interface{}) {
	panic("unreachable")
}

func (a *nodeQueue) Pop() interface{} {
	n := len(*a)
	x := (*a)[n-1]
	x.index = -1 // for safety
	*a = (*a)[:n-1]
	return x
}
<|endoftext|>