<commit_before>package sq

import (
	"encoding/binary"
	"fmt"
	"os"
	"path"
	"sync"
	"syscall"
	"unsafe"
)

const (
	MESSAGE_OVERHEAD = 5 //length + termination
)

var (
	encoder            = binary.LittleEndian
	blank              = struct{}{}
	ChannelNameLenErr  = fmt.Errorf("channel name cannot exceed %d characters", MAX_CHANNEL_NAME_SIZE)
	ChannelExistsErr   = fmt.Errorf("channel already exists")
	ChannelCreateErr   = fmt.Errorf("channel count not be created")
	MessageTooLargeErr = fmt.Errorf("message too large")
	pageSize           = os.Getpagesize()
)

type addChannelWork struct {
	err     error
	channel *Channel
	config  *ChannelConfiguration
	c       chan *addChannelWork
}

type Topic struct {
	path         string
	state        *State
	states       *States
	segmentSize  int
	channelsLock sync.RWMutex
	channels     map[string]*Channel
	segment      *Segment
	segmentsLock sync.RWMutex
	segments     map[uint64]*Segment
	addChannel   chan *addChannelWork
	messageAdded chan struct{}
	dataLock     sync.RWMutex
}

func OpenTopic(name string, config *TopicConfiguration) (*Topic, error) {
	t := &Topic{
		path:         path.Join(config.path, name),
		channels:     make(map[string]*Channel),
		segments:     make(map[uint64]*Segment),
		addChannel:   make(chan *addChannelWork),
		segmentSize:  config.segmentSize,
		messageAdded: make(chan struct{}, 64),
	}
	err := loadStates(t)
	if err != nil {
		return nil, err
	}

	if id := t.state.segmentId; id == 0 {
		if err := t.expand(); err != nil {
			return nil, err
		}
		if err := t.states.syncTopic(); err != nil {
			return nil, err
		}
	} else {
		t.findWritePosition(openSegment(t, id, false))
		t.segments[id] = t.segment
	}
	go t.worker()
	return t, nil
}

func (t *Topic) Write(data []byte) error {
	length := len(data)

	t.dataLock.Lock()
	start := int(t.state.offset)
	dataStart := start + 4
	dataEnd := dataStart + length

	// do we have enough space in the current segment?
	if dataEnd > t.segmentSize {
		if length+MESSAGE_OVERHEAD+int(SEGMENT_HEADER_SIZE) > t.segmentSize {
			return MessageTooLargeErr
		}
		if err := t.expand(); err != nil {
			return err
		}
		start = int(SEGMENT_HEADER_SIZE)
		dataStart = start + 4
		dataEnd = dataStart + length
	}

	// write the message length
	encoder.PutUint32(t.segment.data[start:], uint32(length))
	// write the message
	copy(t.segment.data[dataStart:], data)
	t.segment.data[dataEnd] = 255
	// location of the next write
	t.state.offset = uint32(dataEnd) + 1
	segment := t.segment
	t.dataLock.Unlock()

	// sync the part of the data file we just wrote
	from := start / pageSize * pageSize
	to := dataStart + length + 1 - from
	_, _, errno := syscall.Syscall(syscall.SYS_MSYNC, uintptr(unsafe.Pointer(&segment.data[from])), uintptr(to), syscall.MS_SYNC)
	if errno != 0 {
		return syscall.Errno(errno)
	}

	// notify channels that a new message is waiting
	t.messageAdded <- blank

	return nil
}

func (t *Topic) Channel(name string, config *ChannelConfiguration) (*Channel, error) {
	if len(name) > MAX_CHANNEL_NAME_SIZE {
		return nil, ChannelNameLenErr
	}
	if config == nil {
		config = ConfigureChannel()
	}
	config.name = name
	res := &addChannelWork{
		c:      make(chan *addChannelWork),
		config: config,
	}
	t.addChannel <- res
	<-res.c
	return res.channel, res.err
}

func (t *Topic) expand() error {
	segment := newSegment(t)
	t.segmentsLock.Lock()
	t.segments[segment.id] = segment
	t.segmentsLock.Unlock()
	if t.segment != nil {
		// create a pointer to the next segment id
		t.segment.nextId = segment.id
		t.segment.size = t.state.offset
		if err := t.segment.syncHeader(); err != nil {
			return err
		}
		t.channelsLock.RLock()
		noChannels := len(t.states.channels) == 0
		t.channelsLock.RUnlock()
		if noChannels {
			t.deleteSegment(t.segment.id)
		}
	}
	t.segment = segment
	t.state.offset = SEGMENT_HEADER_SIZE
	t.state.segmentId = segment.id
	return nil
}

func (t *Topic) worker() {
	for {
		select {
		case work := <-t.addChannel:
			work.channel, work.err = t.createChannel(work.config)
			work.c <- work
		case <-t.messageAdded:
			t.channelsLock.RLock()
			for _, c := range t.channels {
				c.notify()
			}
			t.channelsLock.RUnlock()
		}
	}
}

func (t *Topic) createChannel(config *ChannelConfiguration) (*Channel, error) {
	t.channelsLock.Lock()
	_, exists := t.channels[config.name]
	if exists {
		t.channelsLock.Unlock()
		if config.temp {
			// try again until we've created one
			return t.createChannel(config)
		}
		return nil, ChannelExistsErr
	}
	defer t.channelsLock.Unlock()

	c := newChannel(t, config)
	if config.temp {
		c.state = new(State)
	} else {
		c.state = t.states.getOrCreate(c.name)
		if c.state == nil {
			return nil, ChannelCreateErr
		}
	}

	// if we have a temp channel, or a new channel, set the position to the
	// writer's current position
	if config.temp || c.state.segmentId == 0 {
		t.dataLock.RLock()
		c.state.offset = t.state.offset
		c.state.segmentId = t.state.segmentId
		t.dataLock.RUnlock()
	}
	t.channels[c.name] = c
	return c, nil
}

func (t *Topic) read(channel *Channel) []byte {
	state := channel.state

	// no need to lock the channel here since the state of the channel is only
	// ever changed after this point (either to move to the next segment or message)
	t.dataLock.RLock()
	isCurrentSegment := state.segmentId == t.state.segmentId
	isCurrentOffset := state.offset == t.state.offset
	t.dataLock.RUnlock()

	// are we fully caught up with the topic?
	if isCurrentSegment && isCurrentOffset {
		return nil
	}

	segment := t.loadSegment(state.segmentId)
	// If we aren't on the current segment, we might be at the end of an old
	// segment. We can safely read old segments without locking since the only
	// writer (the topic), is done with it
	if !isCurrentSegment {
		if state.offset >= segment.size {
			previousId := state.segmentId
			segment = t.loadSegment(segment.nextId)
			channel.changeSegment(segment)
			if t.isSegmentUsable(previousId) == false {
				t.deleteSegment(previousId)
			}
		}
	}

	l := encoder.Uint32(segment.data[state.offset:])
	start := state.offset + 4
	end := start + uint32(l)
	return segment.data[start:end]
}

func (t *Topic) loadSegment(id uint64) *Segment {
	t.segmentsLock.RLock()
	segment := t.segments[id]
	t.segmentsLock.RUnlock()
	if segment != nil {
		return segment
	}

	t.segmentsLock.Lock()
	defer t.segmentsLock.Unlock()
	if segment := t.segments[id]; segment != nil {
		return segment
	}
	segment = openSegment(t, id, false)
	t.segments[id] = segment
	return segment
}

// A segment is usable if any channel references it or an earlier one
// How we check this depends on whether or not the channel is active
// (currently consuming message). For an active channel, we ask the channel,
// for an inactive channel, we can query the state direclty knowing that
// no one can be writing to it at the same time
func (t *Topic) isSegmentUsable(id uint64) bool {
	t.channelsLock.RLock()
	defer t.channelsLock.RUnlock()
	for name, state := range t.states.channels {
		if channel, active := t.channels[name]; active {
			if channel.isSegmentUsable(id) == true {
				return true
			}
		} else if state.isSegmentUsable(id) == true {
			return true
		}
	}
	return false
}

// The topic's persisted state could be behind from the actual state. However,
// we can determine the actual state based on the data which is guaranteed to be
// up to date (the next reference id and the data itself)
func (t *Topic) findWritePosition(segment *Segment) {
	for segment.nextId != 0 {
		segment = openSegment(t, segment.nextId, false)
	}
	t.segment = segment
	t.state.segmentId = segment.id

	offset := SEGMENT_HEADER_SIZE
	for offset < uint32(t.segmentSize) {
		l := encoder.Uint32(segment.data[offset:])
		if l == 0 {
			break
		}
		if segment.data[offset+l+4] != 255 {
			break
		}
		offset += l + MESSAGE_OVERHEAD
	}
	t.state.offset = offset
}

func (t *Topic) deleteSegment(id uint64) {
	t.segmentsLock.Lock()
	segment := t.segments[id]
	delete(t.segments, id)
	t.segmentsLock.Unlock()
	if segment != nil {
		segment.delete()
	}
}
<commit_msg>Use crc32 to ensure message integrity rather than a simple marker byte. This suggestion came from @ayende and it now means that we no longer require the OS to flush sectors in sequence (which it probably did, but without any guarantee)<commit_after>package sq

import (
	"encoding/binary"
	"fmt"
	"hash/crc32"
	"os"
	"path"
	"sync"
	"syscall"
	"unsafe"
)

const (
	MESSAGE_OVERHEAD = 8 //length + crc32
)

var (
	encoder            = binary.LittleEndian
	blank              = struct{}{}
	ChannelNameLenErr  = fmt.Errorf("channel name cannot exceed %d characters", MAX_CHANNEL_NAME_SIZE)
	ChannelExistsErr   = fmt.Errorf("channel already exists")
	ChannelCreateErr   = fmt.Errorf("channel count not be created")
	MessageTooLargeErr = fmt.Errorf("message too large")
	pageSize           = os.Getpagesize()
)

type addChannelWork struct {
	err     error
	channel *Channel
	config  *ChannelConfiguration
	c       chan *addChannelWork
}

type Topic struct {
	path         string
	state        *State
	states       *States
	segmentSize  int
	channelsLock sync.RWMutex
	channels     map[string]*Channel
	segment      *Segment
	segmentsLock sync.RWMutex
	segments     map[uint64]*Segment
	addChannel   chan *addChannelWork
	messageAdded chan struct{}
	dataLock     sync.RWMutex
}

func OpenTopic(name string, config *TopicConfiguration) (*Topic, error) {
	t := &Topic{
		path:         path.Join(config.path, name),
		channels:     make(map[string]*Channel),
		segments:     make(map[uint64]*Segment),
		addChannel:   make(chan *addChannelWork),
		segmentSize:  config.segmentSize,
		messageAdded: make(chan struct{}, 64),
	}
	err := loadStates(t)
	if err != nil {
		return nil, err
	}

	if id := t.state.segmentId; id == 0 {
		if err := t.expand(); err != nil {
			return nil, err
		}
		if err := t.states.syncTopic(); err != nil {
			return nil, err
		}
	} else {
		t.findWritePosition(openSegment(t, id, false))
		t.segments[id] = t.segment
	}
	go t.worker()
	return t, nil
}

func (t *Topic) Write(data []byte) error {
	length := len(data)

	t.dataLock.Lock()
	start := int(t.state.offset)
	dataStart := start + MESSAGE_OVERHEAD
	dataEnd := dataStart + length

	// do we have enough space in the current segment?
	if dataEnd > t.segmentSize {
		if length+dataStart+int(SEGMENT_HEADER_SIZE) > t.segmentSize {
			return MessageTooLargeErr
		}
		if err := t.expand(); err != nil {
			return err
		}
		start = int(SEGMENT_HEADER_SIZE)
		dataStart = start + MESSAGE_OVERHEAD
		dataEnd = dataStart + length
	}

	// write the message length
	encoder.PutUint32(t.segment.data[start:], uint32(length))
	// write the message's crc
	encoder.PutUint32(t.segment.data[start+4:], crc32.ChecksumIEEE(data))
	// write the message
	copy(t.segment.data[dataStart:], data)

	// location of the next write
	t.state.offset = uint32(dataEnd)
	segment := t.segment
	t.dataLock.Unlock()

	// sync the part of the data file we just wrote
	from := start / pageSize * pageSize
	to := dataStart + length - from
	_, _, errno := syscall.Syscall(syscall.SYS_MSYNC, uintptr(unsafe.Pointer(&segment.data[from])), uintptr(to), syscall.MS_SYNC)
	if errno != 0 {
		return syscall.Errno(errno)
	}

	// notify channels that a new message is waiting
	t.messageAdded <- blank

	return nil
}

func (t *Topic) Channel(name string, config *ChannelConfiguration) (*Channel, error) {
	if len(name) > MAX_CHANNEL_NAME_SIZE {
		return nil, ChannelNameLenErr
	}
	if config == nil {
		config = ConfigureChannel()
	}
	config.name = name
	res := &addChannelWork{
		c:      make(chan *addChannelWork),
		config: config,
	}
	t.addChannel <- res
	<-res.c
	return res.channel, res.err
}

func (t *Topic) expand() error {
	segment := newSegment(t)
	t.segmentsLock.Lock()
	t.segments[segment.id] = segment
	t.segmentsLock.Unlock()
	if t.segment != nil {
		// create a pointer to the next segment id
		t.segment.nextId = segment.id
		t.segment.size = t.state.offset
		if err := t.segment.syncHeader(); err != nil {
			return err
		}
		t.channelsLock.RLock()
		noChannels := len(t.states.channels) == 0
		t.channelsLock.RUnlock()
		if noChannels {
			t.deleteSegment(t.segment.id)
		}
	}
	t.segment = segment
	t.state.offset = SEGMENT_HEADER_SIZE
	t.state.segmentId = segment.id
	return nil
}

func (t *Topic) worker() {
	for {
		select {
		case work := <-t.addChannel:
			work.channel, work.err = t.createChannel(work.config)
			work.c <- work
		case <-t.messageAdded:
			t.channelsLock.RLock()
			for _, c := range t.channels {
				c.notify()
			}
			t.channelsLock.RUnlock()
		}
	}
}

func (t *Topic) createChannel(config *ChannelConfiguration) (*Channel, error) {
	t.channelsLock.Lock()
	_, exists := t.channels[config.name]
	if exists {
		t.channelsLock.Unlock()
		if config.temp {
			// try again until we've created one
			return t.createChannel(config)
		}
		return nil, ChannelExistsErr
	}
	defer t.channelsLock.Unlock()

	c := newChannel(t, config)
	if config.temp {
		c.state = new(State)
	} else {
		c.state = t.states.getOrCreate(c.name)
		if c.state == nil {
			return nil, ChannelCreateErr
		}
	}

	// if we have a temp channel, or a new channel, set the position to the
	// writer's current position
	if config.temp || c.state.segmentId == 0 {
		t.dataLock.RLock()
		c.state.offset = t.state.offset
		c.state.segmentId = t.state.segmentId
		t.dataLock.RUnlock()
	}
	t.channels[c.name] = c
	return c, nil
}

func (t *Topic) read(channel *Channel) []byte {
	state := channel.state

	// no need to lock the channel here since the state of the channel is only
	// ever changed after this point (either to move to the next segment or message)
	t.dataLock.RLock()
	isCurrentSegment := state.segmentId == t.state.segmentId
	isCurrentOffset := state.offset == t.state.offset
	t.dataLock.RUnlock()

	// are we fully caught up with the topic?
	if isCurrentSegment && isCurrentOffset {
		return nil
	}

	segment := t.loadSegment(state.segmentId)
	// If we aren't on the current segment, we might be at the end of an old
	// segment. We can safely read old segments without locking since the only
	// writer (the topic), is done with it
	if !isCurrentSegment {
		if state.offset >= segment.size {
			previousId := state.segmentId
			segment = t.loadSegment(segment.nextId)
			channel.changeSegment(segment)
			if t.isSegmentUsable(previousId) == false {
				t.deleteSegment(previousId)
			}
		}
	}

	l := encoder.Uint32(segment.data[state.offset:])
	start := state.offset + MESSAGE_OVERHEAD
	end := start + uint32(l)
	return segment.data[start:end]
}

func (t *Topic) loadSegment(id uint64) *Segment {
	t.segmentsLock.RLock()
	segment := t.segments[id]
	t.segmentsLock.RUnlock()
	if segment != nil {
		return segment
	}

	t.segmentsLock.Lock()
	defer t.segmentsLock.Unlock()
	if segment := t.segments[id]; segment != nil {
		return segment
	}
	segment = openSegment(t, id, false)
	t.segments[id] = segment
	return segment
}

// A segment is usable if any channel references it or an earlier one
// How we check this depends on whether or not the channel is active
// (currently consuming message). For an active channel, we ask the channel,
// for an inactive channel, we can query the state direclty knowing that
// no one can be writing to it at the same time
func (t *Topic) isSegmentUsable(id uint64) bool {
	t.channelsLock.RLock()
	defer t.channelsLock.RUnlock()
	for name, state := range t.states.channels {
		if channel, active := t.channels[name]; active {
			if channel.isSegmentUsable(id) == true {
				return true
			}
		} else if state.isSegmentUsable(id) == true {
			return true
		}
	}
	return false
}

// The topic's persisted state could be behind from the actual state. However,
// we can determine the actual state based on the data which is guaranteed to be
// up to date (the next reference id and the data itself)
func (t *Topic) findWritePosition(segment *Segment) {
	for segment.nextId != 0 {
		segment = openSegment(t, segment.nextId, false)
	}
	t.segment = segment
	t.state.segmentId = segment.id

	offset := SEGMENT_HEADER_SIZE
	for offset < uint32(t.segmentSize) {
		l := encoder.Uint32(segment.data[offset:])
		if l == 0 {
			break
		}
		hash := encoder.Uint32(segment.data[offset+4:])
		dataStart := offset + 8
		if hash != crc32.ChecksumIEEE(segment.data[dataStart:dataStart+l]) {
			break
		}
		offset += l + MESSAGE_OVERHEAD
	}
	t.state.offset = offset
}

func (t *Topic) deleteSegment(id uint64) {
	t.segmentsLock.Lock()
	segment := t.segments[id]
	delete(t.segments, id)
	t.segmentsLock.Unlock()
	if segment != nil {
		segment.delete()
	}
}
<|endoftext|>


<commit_before>package gps

import (
	"fmt"
	"strconv"
	"strings"
)

const (
	successChar   = "✓"
	successCharSp = successChar + " "
	failChar      = "✗"
	failCharSp    = failChar + " "
	backChar      = "←"
	innerIndent   = "  "
)

func (s *solver) traceCheckPkgs(bmi bimodalIdentifier) {
	if s.tl == nil {
		return
	}

	prefix := getprei(len(s.vqs) + 1)
	s.tl.Printf("%s\n", tracePrefix(fmt.Sprintf("? revisit %s to add %v pkgs", bmi.id.errString(), len(bmi.pl)), prefix, prefix))
}

func (s *solver) traceCheckQueue(q *versionQueue, bmi bimodalIdentifier, cont bool, offset int) {
	if s.tl == nil {
		return
	}

	prefix := getprei(len(s.vqs) + offset)
	vlen := strconv.Itoa(len(q.pi))
	if !q.allLoaded {
		vlen = "at least " + vlen
	}

	// TODO(sdboyer) how...to list the packages in the limited space we have?
	var verb string
	indent := ""
	if cont {
		// Continue is an "inner" message.. indenting
		verb = "continue"
		vlen = vlen + " more"
		indent = innerIndent
	} else {
		verb = "attempt"
	}

	s.tl.Printf("%s\n", tracePrefix(fmt.Sprintf("%s? %s %s with %v pkgs; %s versions to try",indent, verb, bmi.id.errString(), len(bmi.pl), vlen), prefix, prefix))
}

// traceStartBacktrack is called with the bmi that first failed, thus initiating
// backtracking
func (s *solver) traceStartBacktrack(bmi bimodalIdentifier, err error, pkgonly bool) {
	if s.tl == nil {
		return
	}

	var msg string
	if pkgonly {
		msg = fmt.Sprintf("%s%s could not add %v pkgs to %s; begin backtrack",innerIndent, backChar, len(bmi.pl), bmi.id.errString())
	} else {
		msg = fmt.Sprintf("%s%s no more versions of %s to try; begin backtrack",innerIndent, backChar, bmi.id.errString())
	}

	prefix := getprei(len(s.sel.projects))
	s.tl.Printf("%s\n", tracePrefix(msg, prefix, prefix))
}

// traceBacktrack is called when a package or project is poppped off during
// backtracking
func (s *solver) traceBacktrack(bmi bimodalIdentifier, pkgonly bool) {
	if s.tl == nil {
		return
	}

	var msg string
	if pkgonly {
		msg = fmt.Sprintf("%s backtrack: popped %v pkgs from %s", backChar, len(bmi.pl), bmi.id.errString())
	} else {
		msg = fmt.Sprintf("%s backtrack: no more versions of %s to try", backChar, bmi.id.errString())
	}

	prefix := getprei(len(s.sel.projects))
	s.tl.Printf("%s\n", tracePrefix(msg, prefix, prefix))
}

// Called just once after solving has finished, whether success or not
func (s *solver) traceFinish(sol solution, err error) {
	if s.tl == nil {
		return
	}

	if err == nil {
		var pkgcount int
		for _, lp := range sol.Projects() {
			pkgcount += len(lp.pkgs)
		}
		s.tl.Printf("%s%s found solution with %v packages from %v projects",innerIndent, successChar, pkgcount, len(sol.Projects()))
	} else {
		s.tl.Printf("%s%s solving failed",innerIndent, failChar)
	}
}

// traceSelectRoot is called just once, when the root project is selected
func (s *solver) traceSelectRoot(ptree PackageTree, cdeps []completeDep) {
	if s.tl == nil {
		return
	}

	// This duplicates work a bit, but we're in trace mode and it's only once,
	// so who cares
	rm := ptree.ExternalReach(true, true, s.rd.ig)

	s.tl.Printf("Root project is %q", s.rd.rpt.ImportRoot)

	var expkgs int
	for _, cdep := range cdeps {
		expkgs += len(cdep.pl)
	}

	// TODO(sdboyer) include info on ignored pkgs/imports, etc.
	s.tl.Printf(" %v transitively valid internal packages", len(rm))
	s.tl.Printf(" %v external packages imported from %v projects", expkgs, len(cdeps))
	s.tl.Printf("(0)   " + successCharSp + "select (root)")
}

// traceSelect is called when an atom is successfully selected
func (s *solver) traceSelect(awp atomWithPackages, pkgonly bool) {
	if s.tl == nil {
		return
	}

	var msg string
	if pkgonly {
		msg = fmt.Sprintf("%s%s include %v more pkgs from %s",innerIndent, successChar, len(awp.pl), a2vs(awp.a))
	} else {
		msg = fmt.Sprintf("%s select %s w/%v pkgs", successChar, a2vs(awp.a), len(awp.pl))
	}

	prefix := getprei(len(s.sel.projects) - 1)
	s.tl.Printf("%s\n", tracePrefix(msg, prefix, prefix))
}

func (s *solver) traceInfo(args ...interface{}) {
	if s.tl == nil {
		return
	}

	if len(args) == 0 {
		panic("must pass at least one param to traceInfo")
	}

	preflen := len(s.sel.projects)
	var msg string
	switch data := args[0].(type) {
	case string:
		msg = tracePrefix(innerIndent + fmt.Sprintf(data, args[1:]...), "  ", "  ")
	case traceError:
		preflen++
		// We got a special traceError, use its custom method
		msg = tracePrefix(innerIndent + data.traceString(), "  ", failCharSp)
	case error:
		// Regular error; still use the x leader but default Error() string
		msg = tracePrefix(innerIndent + data.Error(), "  ", failCharSp)
	default:
		// panic here because this can *only* mean a stupid internal bug
		panic(fmt.Sprintf("%scanary - unknown type passed as first param to traceInfo %T", innerIndent, data))
	}

	prefix := getprei(preflen)
	s.tl.Printf("%s\n", tracePrefix(msg, prefix, prefix))
}

func getprei(i int) string {
	var s string
	if i < 10 {
		s = fmt.Sprintf("(%d)	", i)
	} else if i < 100 {
		s = fmt.Sprintf("(%d)  ", i)
	} else {
		s = fmt.Sprintf("(%d) ", i)
	}
	return s
}

func tracePrefix(msg, sep, fsep string) string {
	parts := strings.Split(strings.TrimSuffix(msg, "\n"), "\n")
	for k, str := range parts {
		if k == 0 {
			parts[k] = fsep + str
		} else {
			parts[k] = sep + str
		}
	}

	return strings.Join(parts, "\n")
}
<commit_msg>Remove indent on panic<commit_after>package gps

import (
	"fmt"
	"strconv"
	"strings"
)

const (
	successChar   = "✓"
	successCharSp = successChar + " "
	failChar      = "✗"
	failCharSp    = failChar + " "
	backChar      = "←"
	innerIndent   = "  "
)

func (s *solver) traceCheckPkgs(bmi bimodalIdentifier) {
	if s.tl == nil {
		return
	}

	prefix := getprei(len(s.vqs) + 1)
	s.tl.Printf("%s\n", tracePrefix(fmt.Sprintf("? revisit %s to add %v pkgs", bmi.id.errString(), len(bmi.pl)), prefix, prefix))
}

func (s *solver) traceCheckQueue(q *versionQueue, bmi bimodalIdentifier, cont bool, offset int) {
	if s.tl == nil {
		return
	}

	prefix := getprei(len(s.vqs) + offset)
	vlen := strconv.Itoa(len(q.pi))
	if !q.allLoaded {
		vlen = "at least " + vlen
	}

	// TODO(sdboyer) how...to list the packages in the limited space we have?
	var verb string
	indent := ""
	if cont {
		// Continue is an "inner" message.. indenting
		verb = "continue"
		vlen = vlen + " more"
		indent = innerIndent
	} else {
		verb = "attempt"
	}

	s.tl.Printf("%s\n", tracePrefix(fmt.Sprintf("%s? %s %s with %v pkgs; %s versions to try",indent, verb, bmi.id.errString(), len(bmi.pl), vlen), prefix, prefix))
}

// traceStartBacktrack is called with the bmi that first failed, thus initiating
// backtracking
func (s *solver) traceStartBacktrack(bmi bimodalIdentifier, err error, pkgonly bool) {
	if s.tl == nil {
		return
	}

	var msg string
	if pkgonly {
		msg = fmt.Sprintf("%s%s could not add %v pkgs to %s; begin backtrack",innerIndent, backChar, len(bmi.pl), bmi.id.errString())
	} else {
		msg = fmt.Sprintf("%s%s no more versions of %s to try; begin backtrack",innerIndent, backChar, bmi.id.errString())
	}

	prefix := getprei(len(s.sel.projects))
	s.tl.Printf("%s\n", tracePrefix(msg, prefix, prefix))
}

// traceBacktrack is called when a package or project is poppped off during
// backtracking
func (s *solver) traceBacktrack(bmi bimodalIdentifier, pkgonly bool) {
	if s.tl == nil {
		return
	}

	var msg string
	if pkgonly {
		msg = fmt.Sprintf("%s backtrack: popped %v pkgs from %s", backChar, len(bmi.pl), bmi.id.errString())
	} else {
		msg = fmt.Sprintf("%s backtrack: no more versions of %s to try", backChar, bmi.id.errString())
	}

	prefix := getprei(len(s.sel.projects))
	s.tl.Printf("%s\n", tracePrefix(msg, prefix, prefix))
}

// Called just once after solving has finished, whether success or not
func (s *solver) traceFinish(sol solution, err error) {
	if s.tl == nil {
		return
	}

	if err == nil {
		var pkgcount int
		for _, lp := range sol.Projects() {
			pkgcount += len(lp.pkgs)
		}
		s.tl.Printf("%s%s found solution with %v packages from %v projects",innerIndent, successChar, pkgcount, len(sol.Projects()))
	} else {
		s.tl.Printf("%s%s solving failed",innerIndent, failChar)
	}
}

// traceSelectRoot is called just once, when the root project is selected
func (s *solver) traceSelectRoot(ptree PackageTree, cdeps []completeDep) {
	if s.tl == nil {
		return
	}

	// This duplicates work a bit, but we're in trace mode and it's only once,
	// so who cares
	rm := ptree.ExternalReach(true, true, s.rd.ig)

	s.tl.Printf("Root project is %q", s.rd.rpt.ImportRoot)

	var expkgs int
	for _, cdep := range cdeps {
		expkgs += len(cdep.pl)
	}

	// TODO(sdboyer) include info on ignored pkgs/imports, etc.
	s.tl.Printf(" %v transitively valid internal packages", len(rm))
	s.tl.Printf(" %v external packages imported from %v projects", expkgs, len(cdeps))
	s.tl.Printf("(0)   " + successCharSp + "select (root)")
}

// traceSelect is called when an atom is successfully selected
func (s *solver) traceSelect(awp atomWithPackages, pkgonly bool) {
	if s.tl == nil {
		return
	}

	var msg string
	if pkgonly {
		msg = fmt.Sprintf("%s%s include %v more pkgs from %s",innerIndent, successChar, len(awp.pl), a2vs(awp.a))
	} else {
		msg = fmt.Sprintf("%s select %s w/%v pkgs", successChar, a2vs(awp.a), len(awp.pl))
	}

	prefix := getprei(len(s.sel.projects) - 1)
	s.tl.Printf("%s\n", tracePrefix(msg, prefix, prefix))
}

func (s *solver) traceInfo(args ...interface{}) {
	if s.tl == nil {
		return
	}

	if len(args) == 0 {
		panic("must pass at least one param to traceInfo")
	}

	preflen := len(s.sel.projects)
	var msg string
	switch data := args[0].(type) {
	case string:
		msg = tracePrefix(innerIndent + fmt.Sprintf(data, args[1:]...), "  ", "  ")
	case traceError:
		preflen++
		// We got a special traceError, use its custom method
		msg = tracePrefix(innerIndent + data.traceString(), "  ", failCharSp)
	case error:
		// Regular error; still use the x leader but default Error() string
		msg = tracePrefix(innerIndent + data.Error(), "  ", failCharSp)
	default:
		// panic here because this can *only* mean a stupid internal bug
		panic(fmt.Sprintf("%canary - unknown type passed as first param to traceInfo %T", data))
	}

	prefix := getprei(preflen)
	s.tl.Printf("%s\n", tracePrefix(msg, prefix, prefix))
}

func getprei(i int) string {
	var s string
	if i < 10 {
		s = fmt.Sprintf("(%d)	", i)
	} else if i < 100 {
		s = fmt.Sprintf("(%d)  ", i)
	} else {
		s = fmt.Sprintf("(%d) ", i)
	}
	return s
}

func tracePrefix(msg, sep, fsep string) string {
	parts := strings.Split(strings.TrimSuffix(msg, "\n"), "\n")
	for k, str := range parts {
		if k == 0 {
			parts[k] = fsep + str
		} else {
			parts[k] = sep + str
		}
	}

	return strings.Join(parts, "\n")
}
<|endoftext|>


<commit_before>package hamt32

import "strings"

type pathT []tableI

// Constructs an empty pathT object.
func newPathT() pathT {
	return pathT(make([]tableI, 0, MaxDepth))
}

// path.peek() returns the last entry without inserted with path.push(...)
// modifying path.
func (path pathT) peek() tableI {
	if len(path) == 0 {
		return nil
	}
	return path[len(path)-1]
}

// path.pop() returns & remmoves the last entry inserted with path.push(...).
func (path *pathT) pop() tableI {
	if len(*path) == 0 {
		//should I do this or let the runtime panic on index out of range
		return nil
	}
	parent := (*path)[len(*path)-1]
	*path = (*path)[:len(*path)-1]
	return parent

}

// Put a new tableI in the path object.
// You should never push nil, but we are not checking to prevent this.
func (path *pathT) push(node tableI) {
	//_ = ASSERT && Assert(node != nil, "pathT.push(nil) not allowed")
	*path = append(*path, node)
}

// path.isEmpty() returns true if there are no entries in the path object,
// otherwise it returns false.
func (path *pathT) isEmpty() bool {
	return len(*path) == 0
}

// Convert path to a string representation. This is only good for debug messages.
// It is not a string format to convert back from.
func (path *pathT) String() string {
	pvs := []tableI(*path)
	strs := make([]string, len(*path))
	var indent = ""
	for i, pv := range pvs {
		strs[i] = indent + pv.String() + "\n"
		indent += "  "
	}
	return strings.Join(strs, "")
}
<commit_msg>deleted path.go (renamed to stack.go)<commit_after><|endoftext|>


<commit_before>package gkvlite

// The core algorithms for treaps are straightforward.  However, that
// algorithmic simplicity is obscured by the additional useful
// features of gkvlite, such as persistence, garbage-avoidance, stats
// tracking, and error handling.  For a simple, memory-only
// implementation of the union/split/join treap algorithms that may be
// easier to understand, see:
// https://github.com/steveyen/gtreap/blob/master/treap.go

// Memory management rules: the union/split/join functions will not
// free their input nodeLoc's, but are responsible instead for
// invoking markReclaimable() on the directly pointed-at input nodes.
// The union/split/join functions must copy the input nodeLoc's if
// they wish to keep the nodeLoc's data.
//
// The caller is responsible for freeing the returned nodeLoc's and
// (if appropriate) the input nodeLoc's.  The caller also takes
// responsibility for markReclaimable() on returned output nodes.

// Returns a treap that is the union of this treap and that treap.
func (o *Store) union(t *Collection, this *nodeLoc, that *nodeLoc) (
	res *nodeLoc, err error) {
	thisNode, err := this.read(o)
	if err != nil {
		return empty_nodeLoc, err
	}
	thatNode, err := that.read(o)
	if err != nil {
		return empty_nodeLoc, err
	}
	if this.isEmpty() || thisNode == nil {
		return t.mkNodeLoc(nil).Copy(that), nil
	}
	if that.isEmpty() || thatNode == nil {
		return t.mkNodeLoc(nil).Copy(this), nil
	}
	thisItemLoc := &thisNode.item
	thisItem, err := thisItemLoc.read(t, false)
	if err != nil {
		return empty_nodeLoc, err
	}
	thatItemLoc := &thatNode.item
	thatItem, err := thatItemLoc.read(t, false)
	if err != nil {
		return empty_nodeLoc, err
	}
	if thisItem.Priority > thatItem.Priority {
		left, middle, right, err := o.split(t, that, thisItem.Key)
		if err != nil {
			return empty_nodeLoc, err
		}
		newLeft, err := o.union(t, &thisNode.left, left)
		if err != nil {
			return empty_nodeLoc, err
		}
		newRight, err := o.union(t, &thisNode.right, right)
		if err != nil {
			return empty_nodeLoc, err
		}
		leftNum, leftBytes, rightNum, rightBytes, err :=
			numInfo(o, newLeft, newRight)
		if err != nil {
			return empty_nodeLoc, err
		}
		var middleNode *node
		if !middle.isEmpty() {
			middleNode, err = middle.read(o)
			if err != nil {
				return empty_nodeLoc, err
			}
			middleItemLoc := &middleNode.item
			middleItem, err := middleItemLoc.read(t, false)
			if err != nil {
				return empty_nodeLoc, err
			}
			res = t.mkNodeLoc(t.mkNode(middleItemLoc, newLeft, newRight,
				leftNum+rightNum+1,
				leftBytes+rightBytes+uint64(middleItem.NumBytes(t))))
		} else {
			res = t.mkNodeLoc(t.mkNode(thisItemLoc, newLeft, newRight,
				leftNum+rightNum+1,
				leftBytes+rightBytes+uint64(thisItem.NumBytes(t))))
		}
		t.freeNodeLoc(left)
		t.freeNodeLoc(right)
		t.freeNodeLoc(middle)
		t.freeNodeLoc(newLeft)
		t.freeNodeLoc(newRight)
		t.markReclaimable(thisNode)
		t.markReclaimable(middleNode)
		return res, nil
	}
	// We don't use middle because the "that" node has precedence.
	left, middle, right, err := o.split(t, this, thatItem.Key)
	if err != nil {
		return empty_nodeLoc, err
	}
	newLeft, err := o.union(t, left, &thatNode.left)
	if err != nil {
		return empty_nodeLoc, err
	}
	newRight, err := o.union(t, right, &thatNode.right)
	if err != nil {
		return empty_nodeLoc, err
	}
	leftNum, leftBytes, rightNum, rightBytes, err :=
		numInfo(o, newLeft, newRight)
	if err != nil {
		return empty_nodeLoc, err
	}
	res = t.mkNodeLoc(t.mkNode(thatItemLoc, newLeft, newRight,
		leftNum+rightNum+1,
		leftBytes+rightBytes+uint64(thatItem.NumBytes(t))))
	middleNode := middle.Node()
	t.freeNodeLoc(left)
	t.freeNodeLoc(right)
	t.freeNodeLoc(middle)
	t.freeNodeLoc(newLeft)
	t.freeNodeLoc(newRight)
	t.markReclaimable(thatNode)
	t.markReclaimable(middleNode)
	return res, nil
}

// Splits a treap into two treaps based on a split key "s".  The
// result is (left, middle, right), where left treap has keys < s,
// right treap has keys > s, and middle is either...
// * empty/nil - meaning key s was not in the original treap.
// * non-empty - returning the original nodeLoc/item that had key s.
func (o *Store) split(t *Collection, n *nodeLoc, s []byte) (
	*nodeLoc, *nodeLoc, *nodeLoc, error) {
	nNode, err := n.read(o)
	if err != nil || n.isEmpty() || nNode == nil {
		return empty_nodeLoc, empty_nodeLoc, empty_nodeLoc, err
	}

	nItemLoc := &nNode.item
	nItem, err := nItemLoc.read(t, false)
	if err != nil {
		return empty_nodeLoc, empty_nodeLoc, empty_nodeLoc, err
	}

	c := t.compare(s, nItem.Key)
	if c == 0 {
		left := t.mkNodeLoc(nil).Copy(&nNode.left)
		right := t.mkNodeLoc(nil).Copy(&nNode.right)
		middle := t.mkNodeLoc(nil).Copy(n)
		return left, middle, right, nil
	}

	if c < 0 {
		if nNode.left.isEmpty() {
			return empty_nodeLoc, empty_nodeLoc, t.mkNodeLoc(nil).Copy(n), nil
		}
		left, middle, right, err := o.split(t, &nNode.left, s)
		if err != nil {
			return empty_nodeLoc, empty_nodeLoc, empty_nodeLoc, err
		}
		leftNum, leftBytes, rightNum, rightBytes, err := numInfo(o, right, &nNode.right)
		if err != nil {
			return empty_nodeLoc, empty_nodeLoc, empty_nodeLoc, err
		}
		newRight := t.mkNodeLoc(t.mkNode(nItemLoc, right, &nNode.right,
			leftNum+rightNum+1,
			leftBytes+rightBytes+uint64(nItem.NumBytes(t))))
		t.freeNodeLoc(right)
		t.markReclaimable(nNode)
		return left, middle, newRight, nil
	}

	if nNode.right.isEmpty() {
		return t.mkNodeLoc(nil).Copy(n), empty_nodeLoc, empty_nodeLoc, nil
	}
	left, middle, right, err := o.split(t, &nNode.right, s)
	if err != nil {
		return empty_nodeLoc, empty_nodeLoc, empty_nodeLoc, err
	}
	leftNum, leftBytes, rightNum, rightBytes, err := numInfo(o, &nNode.left, left)
	if err != nil {
		return empty_nodeLoc, empty_nodeLoc, empty_nodeLoc, err
	}
	newLeft := t.mkNodeLoc(t.mkNode(nItemLoc, &nNode.left, left,
		leftNum+rightNum+1,
		leftBytes+rightBytes+uint64(nItem.NumBytes(t))))
	t.freeNodeLoc(left)
	t.markReclaimable(nNode)
	return newLeft, middle, right, nil
}

// Joins this treap and that treap into one treap.  Unlike union(),
// the join() function assumes all keys from this treap should be less
// than keys from that treap.
func (o *Store) join(t *Collection, this *nodeLoc, that *nodeLoc) (
	res *nodeLoc, err error) {
	thisNode, err := this.read(o)
	if err != nil {
		return empty_nodeLoc, err
	}
	thatNode, err := that.read(o)
	if err != nil {
		return empty_nodeLoc, err
	}
	if this.isEmpty() || thisNode == nil {
		return t.mkNodeLoc(nil).Copy(that), nil
	}
	if that.isEmpty() || thatNode == nil {
		return t.mkNodeLoc(nil).Copy(this), nil
	}
	thisItemLoc := &thisNode.item
	thisItem, err := thisItemLoc.read(t, false)
	if err != nil {
		return empty_nodeLoc, err
	}
	thatItemLoc := &thatNode.item
	thatItem, err := thatItemLoc.read(t, false)
	if err != nil {
		return empty_nodeLoc, err
	}
	if thisItem.Priority > thatItem.Priority {
		newRight, err := o.join(t, &thisNode.right, that)
		if err != nil {
			return empty_nodeLoc, err
		}
		leftNum, leftBytes, rightNum, rightBytes, err :=
			numInfo(o, &thisNode.left, newRight)
		if err != nil {
			return empty_nodeLoc, err
		}
		res = t.mkNodeLoc(t.mkNode(thisItemLoc, &thisNode.left, newRight,
			leftNum+rightNum+1,
			leftBytes+rightBytes+uint64(thisItem.NumBytes(t))))
		t.markReclaimable(thisNode)
		t.freeNodeLoc(newRight)
		return res, nil
	}
	newLeft, err := o.join(t, this, &thatNode.left)
	if err != nil {
		return empty_nodeLoc, err
	}
	leftNum, leftBytes, rightNum, rightBytes, err :=
		numInfo(o, newLeft, &thatNode.right)
	if err != nil {
		return empty_nodeLoc, err
	}
	res = t.mkNodeLoc(t.mkNode(thatItemLoc, newLeft, &thatNode.right,
		leftNum+rightNum+1,
		leftBytes+rightBytes+uint64(thatItem.NumBytes(t))))
	t.markReclaimable(thatNode)
	t.freeNodeLoc(newLeft)
	return res, nil
}

func (o *Store) walk(t *Collection, withValue bool, cfn func(*node) (*nodeLoc, bool)) (
	res *Item, err error) {
	rnl := t.rootAddRef()
	defer t.rootDecRef(rnl)
	n := rnl.root
	nNode, err := n.read(o)
	if err != nil || n.isEmpty() || nNode == nil {
		return nil, err
	}
	for {
		child, ok := cfn(nNode)
		if !ok {
			return nil, nil
		}
		childNode, err := child.read(o)
		if err != nil {
			return nil, err
		}
		if child.isEmpty() || childNode == nil {
			i, err := nNode.item.read(t, withValue)
			if err != nil {
				return nil, err
			}
			return i, nil
		}
		nNode = childNode
	}
}

func (o *Store) visitNodes(t *Collection, n *nodeLoc, target []byte,
	withValue bool, visitor ItemVisitorEx, depth uint64,
	choiceFunc func(int, *node) (bool, *nodeLoc, *nodeLoc)) (bool, error) {
	nNode, err := n.read(o)
	if err != nil {
		return false, err
	}
	if n.isEmpty() || nNode == nil {
		return true, nil
	}
	nItemLoc := &nNode.item
	nItem, err := nItemLoc.read(t, false)
	if err != nil {
		return false, err
	}
	choice, choiceT, choiceF := choiceFunc(t.compare(target, nItem.Key), nNode)
	if choice {
		keepGoing, err :=
			o.visitNodes(t, choiceT, target, withValue, visitor, depth+1, choiceFunc)
		if err != nil || !keepGoing {
			return false, err
		}
		nItem, err := nItemLoc.read(t, withValue)
		if err != nil {
			return false, err
		}
		if !visitor(nItem, depth) {
			return false, nil
		}
	}
	return o.visitNodes(t, choiceF, target, withValue, visitor, depth+1, choiceFunc)
}
<commit_msg>Extra panic if key is nil.<commit_after>package gkvlite

import (
	"fmt"
)

// The core algorithms for treaps are straightforward.  However, that
// algorithmic simplicity is obscured by the additional useful
// features of gkvlite, such as persistence, garbage-avoidance, stats
// tracking, and error handling.  For a simple, memory-only
// implementation of the union/split/join treap algorithms that may be
// easier to understand, see:
// https://github.com/steveyen/gtreap/blob/master/treap.go

// Memory management rules: the union/split/join functions will not
// free their input nodeLoc's, but are responsible instead for
// invoking markReclaimable() on the directly pointed-at input nodes.
// The union/split/join functions must copy the input nodeLoc's if
// they wish to keep the nodeLoc's data.
//
// The caller is responsible for freeing the returned nodeLoc's and
// (if appropriate) the input nodeLoc's.  The caller also takes
// responsibility for markReclaimable() on returned output nodes.

// Returns a treap that is the union of this treap and that treap.
func (o *Store) union(t *Collection, this *nodeLoc, that *nodeLoc) (
	res *nodeLoc, err error) {
	thisNode, err := this.read(o)
	if err != nil {
		return empty_nodeLoc, err
	}
	thatNode, err := that.read(o)
	if err != nil {
		return empty_nodeLoc, err
	}
	if this.isEmpty() || thisNode == nil {
		return t.mkNodeLoc(nil).Copy(that), nil
	}
	if that.isEmpty() || thatNode == nil {
		return t.mkNodeLoc(nil).Copy(this), nil
	}
	thisItemLoc := &thisNode.item
	thisItem, err := thisItemLoc.read(t, false)
	if err != nil {
		return empty_nodeLoc, err
	}
	thatItemLoc := &thatNode.item
	thatItem, err := thatItemLoc.read(t, false)
	if err != nil {
		return empty_nodeLoc, err
	}
	if thisItem.Priority > thatItem.Priority {
		left, middle, right, err := o.split(t, that, thisItem.Key)
		if err != nil {
			return empty_nodeLoc, err
		}
		newLeft, err := o.union(t, &thisNode.left, left)
		if err != nil {
			return empty_nodeLoc, err
		}
		newRight, err := o.union(t, &thisNode.right, right)
		if err != nil {
			return empty_nodeLoc, err
		}
		leftNum, leftBytes, rightNum, rightBytes, err :=
			numInfo(o, newLeft, newRight)
		if err != nil {
			return empty_nodeLoc, err
		}
		var middleNode *node
		if !middle.isEmpty() {
			middleNode, err = middle.read(o)
			if err != nil {
				return empty_nodeLoc, err
			}
			middleItemLoc := &middleNode.item
			middleItem, err := middleItemLoc.read(t, false)
			if err != nil {
				return empty_nodeLoc, err
			}
			res = t.mkNodeLoc(t.mkNode(middleItemLoc, newLeft, newRight,
				leftNum+rightNum+1,
				leftBytes+rightBytes+uint64(middleItem.NumBytes(t))))
		} else {
			res = t.mkNodeLoc(t.mkNode(thisItemLoc, newLeft, newRight,
				leftNum+rightNum+1,
				leftBytes+rightBytes+uint64(thisItem.NumBytes(t))))
		}
		t.freeNodeLoc(left)
		t.freeNodeLoc(right)
		t.freeNodeLoc(middle)
		t.freeNodeLoc(newLeft)
		t.freeNodeLoc(newRight)
		t.markReclaimable(thisNode)
		t.markReclaimable(middleNode)
		return res, nil
	}
	// We don't use middle because the "that" node has precedence.
	left, middle, right, err := o.split(t, this, thatItem.Key)
	if err != nil {
		return empty_nodeLoc, err
	}
	newLeft, err := o.union(t, left, &thatNode.left)
	if err != nil {
		return empty_nodeLoc, err
	}
	newRight, err := o.union(t, right, &thatNode.right)
	if err != nil {
		return empty_nodeLoc, err
	}
	leftNum, leftBytes, rightNum, rightBytes, err :=
		numInfo(o, newLeft, newRight)
	if err != nil {
		return empty_nodeLoc, err
	}
	res = t.mkNodeLoc(t.mkNode(thatItemLoc, newLeft, newRight,
		leftNum+rightNum+1,
		leftBytes+rightBytes+uint64(thatItem.NumBytes(t))))
	middleNode := middle.Node()
	t.freeNodeLoc(left)
	t.freeNodeLoc(right)
	t.freeNodeLoc(middle)
	t.freeNodeLoc(newLeft)
	t.freeNodeLoc(newRight)
	t.markReclaimable(thatNode)
	t.markReclaimable(middleNode)
	return res, nil
}

// Splits a treap into two treaps based on a split key "s".  The
// result is (left, middle, right), where left treap has keys < s,
// right treap has keys > s, and middle is either...
// * empty/nil - meaning key s was not in the original treap.
// * non-empty - returning the original nodeLoc/item that had key s.
func (o *Store) split(t *Collection, n *nodeLoc, s []byte) (
	*nodeLoc, *nodeLoc, *nodeLoc, error) {
	nNode, err := n.read(o)
	if err != nil || n.isEmpty() || nNode == nil {
		return empty_nodeLoc, empty_nodeLoc, empty_nodeLoc, err
	}

	nItemLoc := &nNode.item
	nItem, err := nItemLoc.read(t, false)
	if err != nil {
		return empty_nodeLoc, empty_nodeLoc, empty_nodeLoc, err
	}

	c := t.compare(s, nItem.Key)
	if c == 0 {
		left := t.mkNodeLoc(nil).Copy(&nNode.left)
		right := t.mkNodeLoc(nil).Copy(&nNode.right)
		middle := t.mkNodeLoc(nil).Copy(n)
		return left, middle, right, nil
	}

	if c < 0 {
		if nNode.left.isEmpty() {
			return empty_nodeLoc, empty_nodeLoc, t.mkNodeLoc(nil).Copy(n), nil
		}
		left, middle, right, err := o.split(t, &nNode.left, s)
		if err != nil {
			return empty_nodeLoc, empty_nodeLoc, empty_nodeLoc, err
		}
		leftNum, leftBytes, rightNum, rightBytes, err := numInfo(o, right, &nNode.right)
		if err != nil {
			return empty_nodeLoc, empty_nodeLoc, empty_nodeLoc, err
		}
		newRight := t.mkNodeLoc(t.mkNode(nItemLoc, right, &nNode.right,
			leftNum+rightNum+1,
			leftBytes+rightBytes+uint64(nItem.NumBytes(t))))
		t.freeNodeLoc(right)
		t.markReclaimable(nNode)
		return left, middle, newRight, nil
	}

	if nNode.right.isEmpty() {
		return t.mkNodeLoc(nil).Copy(n), empty_nodeLoc, empty_nodeLoc, nil
	}
	left, middle, right, err := o.split(t, &nNode.right, s)
	if err != nil {
		return empty_nodeLoc, empty_nodeLoc, empty_nodeLoc, err
	}
	leftNum, leftBytes, rightNum, rightBytes, err := numInfo(o, &nNode.left, left)
	if err != nil {
		return empty_nodeLoc, empty_nodeLoc, empty_nodeLoc, err
	}
	newLeft := t.mkNodeLoc(t.mkNode(nItemLoc, &nNode.left, left,
		leftNum+rightNum+1,
		leftBytes+rightBytes+uint64(nItem.NumBytes(t))))
	t.freeNodeLoc(left)
	t.markReclaimable(nNode)
	return newLeft, middle, right, nil
}

// Joins this treap and that treap into one treap.  Unlike union(),
// the join() function assumes all keys from this treap should be less
// than keys from that treap.
func (o *Store) join(t *Collection, this *nodeLoc, that *nodeLoc) (
	res *nodeLoc, err error) {
	thisNode, err := this.read(o)
	if err != nil {
		return empty_nodeLoc, err
	}
	thatNode, err := that.read(o)
	if err != nil {
		return empty_nodeLoc, err
	}
	if this.isEmpty() || thisNode == nil {
		return t.mkNodeLoc(nil).Copy(that), nil
	}
	if that.isEmpty() || thatNode == nil {
		return t.mkNodeLoc(nil).Copy(this), nil
	}
	thisItemLoc := &thisNode.item
	thisItem, err := thisItemLoc.read(t, false)
	if err != nil {
		return empty_nodeLoc, err
	}
	thatItemLoc := &thatNode.item
	thatItem, err := thatItemLoc.read(t, false)
	if err != nil {
		return empty_nodeLoc, err
	}
	if thisItem.Priority > thatItem.Priority {
		newRight, err := o.join(t, &thisNode.right, that)
		if err != nil {
			return empty_nodeLoc, err
		}
		leftNum, leftBytes, rightNum, rightBytes, err :=
			numInfo(o, &thisNode.left, newRight)
		if err != nil {
			return empty_nodeLoc, err
		}
		res = t.mkNodeLoc(t.mkNode(thisItemLoc, &thisNode.left, newRight,
			leftNum+rightNum+1,
			leftBytes+rightBytes+uint64(thisItem.NumBytes(t))))
		t.markReclaimable(thisNode)
		t.freeNodeLoc(newRight)
		return res, nil
	}
	newLeft, err := o.join(t, this, &thatNode.left)
	if err != nil {
		return empty_nodeLoc, err
	}
	leftNum, leftBytes, rightNum, rightBytes, err :=
		numInfo(o, newLeft, &thatNode.right)
	if err != nil {
		return empty_nodeLoc, err
	}
	res = t.mkNodeLoc(t.mkNode(thatItemLoc, newLeft, &thatNode.right,
		leftNum+rightNum+1,
		leftBytes+rightBytes+uint64(thatItem.NumBytes(t))))
	t.markReclaimable(thatNode)
	t.freeNodeLoc(newLeft)
	return res, nil
}

func (o *Store) walk(t *Collection, withValue bool, cfn func(*node) (*nodeLoc, bool)) (
	res *Item, err error) {
	rnl := t.rootAddRef()
	defer t.rootDecRef(rnl)
	n := rnl.root
	nNode, err := n.read(o)
	if err != nil || n.isEmpty() || nNode == nil {
		return nil, err
	}
	for {
		child, ok := cfn(nNode)
		if !ok {
			return nil, nil
		}
		childNode, err := child.read(o)
		if err != nil {
			return nil, err
		}
		if child.isEmpty() || childNode == nil {
			i, err := nNode.item.read(t, withValue)
			if err != nil {
				return nil, err
			}
			return i, nil
		}
		nNode = childNode
	}
}

func (o *Store) visitNodes(t *Collection, n *nodeLoc, target []byte,
	withValue bool, visitor ItemVisitorEx, depth uint64,
	choiceFunc func(int, *node) (bool, *nodeLoc, *nodeLoc)) (bool, error) {
	nNode, err := n.read(o)
	if err != nil {
		return false, err
	}
	if n.isEmpty() || nNode == nil {
		return true, nil
	}
	nItemLoc := &nNode.item
	nItem, err := nItemLoc.read(t, false)
	if err != nil {
		return false, err
	}
	if nItem == nil {
		panic(fmt.Sprintf("visitNodes nItem nil: %#v", nNode))
	}
	choice, choiceT, choiceF := choiceFunc(t.compare(target, nItem.Key), nNode)
	if choice {
		keepGoing, err :=
			o.visitNodes(t, choiceT, target, withValue, visitor, depth+1, choiceFunc)
		if err != nil || !keepGoing {
			return false, err
		}
		nItem, err := nItemLoc.read(t, withValue)
		if err != nil {
			return false, err
		}
		if !visitor(nItem, depth) {
			return false, nil
		}
	}
	return o.visitNodes(t, choiceF, target, withValue, visitor, depth+1, choiceFunc)
}
<|endoftext|>


<commit_before>package terraform

import (
	"io"
	"os/exec"
)

// Apply takes a terraform config and applies it
func (client *Client) Apply(dryrun bool) error {
	action := "apply"
	if dryrun {
		action = "plan"
	}
	return client.terraform([]string{
		action,
		"-input=false",
	}, client.stdout)
}

// Destroy destroys the given terraform config
func (client *Client) Destroy() error {
	return client.terraform([]string{
		"destroy",
		"-force",
	}, client.stdout)
}

func (client *Client) terraform(args []string, stdout io.Writer) error {
	cmd := exec.Command(client.tempDir.Path("terraform"), args...)
	cmd.Dir = client.configDir
	cmd.Stdout = stdout
	cmd.Stderr = client.stderr
	return cmd.Run()
}
<commit_msg>add terraform debugging<commit_after>package terraform

import (
	"fmt"
	"io"
	"os"
	"os/exec"
)

// Apply takes a terraform config and applies it
func (client *Client) Apply(dryrun bool) error {
	fmt.Println("RUNNING TERRAFORM APPLY")
	action := "apply"
	if dryrun {
		action = "plan"
	}
	os.Setenv("TF_LOG", "TRACE")
	return client.terraform([]string{
		action,
		"-input=false",
	}, client.stdout)
}

// Destroy destroys the given terraform config
func (client *Client) Destroy() error {
	return client.terraform([]string{
		"destroy",
		"-force",
	}, client.stdout)
}

func (client *Client) terraform(args []string, stdout io.Writer) error {
	cmd := exec.Command(client.tempDir.Path("terraform"), args...)
	cmd.Dir = client.configDir
	cmd.Stdout = stdout
	cmd.Stderr = client.stderr
	return cmd.Run()
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"
	"os"
	"reflect"
	"strconv"
	"strings"

	"github.com/chzyer/readline"
	"github.com/jamesnetherton/homehub-client"
	"github.com/spf13/cobra"
	"github.com/spf13/cobra/cobra/cmd"
)

var (
	hubURL   string
	userName string
	password string
	hub      *homehub.Hub
)

func main() {
	cmd.RootCmd.PersistentFlags().StringVarP(&hubURL, "huburl", "r", "http://192.168.1.254", "URL of the home hub router")
	cmd.RootCmd.PersistentFlags().StringVarP(&userName, "username", "u", "admin", "The hub router user name")
	cmd.RootCmd.PersistentFlags().StringVarP(&password, "password", "p", "", "The home hub router password")

	cmdHandler := func(cmd *cobra.Command, args []string) {
		if !stringIsEmpty(hubURL) && !stringIsEmpty(userName) && !stringIsEmpty(password) {
			hub = homehub.New(hubURL, userName, password)
			success, _ := hub.Login()

			if !success {
				fmt.Println("Login failed")
				return
			}

			invokeMethod(cmd.Name())
		} else {
			cmd.Usage()
		}
	}

	for _, funcName := range getFuncNames() {
		cmd.RootCmd.AddCommand(&cobra.Command{
			Use: funcName,
			Run: cmdHandler,
		})
	}

	helpFunc := func(cmd *cobra.Command, args []string) {
		fmt.Println("Usage:\n  homehub-cli [command] --huburl=<home hub url> --username=<home hub username> --password=<home hub password>")
		fmt.Println("\nCommands:\n ", strings.Join(getFuncNames(), "\n  "))
	}

	usageFunc := func(cmd *cobra.Command) error {
		fmt.Printf("Usage:\n  homehub-cli %s --huburl=<home hub url> --username=<home hub username> --password=<home hub password>\n", cmd.Name())
		return nil
	}

	cmd.RootCmd.SetHelpFunc(helpFunc)
	cmd.RootCmd.SetUsageFunc(usageFunc)
	cmd.RootCmd.SilenceErrors = true

	if len(os.Args[1:]) == 0 {
		banner()

		l, err := createReadline()
		if err != nil {
			panic(err)
		}
		defer l.Close()

		for {
			line, err := l.Readline()

			if err == readline.ErrInterrupt {
				if len(line) == 0 {
					break
				} else {
					continue
				}
			} else if err == io.EOF {
				break
			}

			line = strings.TrimSpace(line)
			if !stringIsEmpty(line) {
				if line != "Login" {
					invokeMethod(line)
				} else {
					hub = doLogin(l)
				}
			}
		}
	} else {
		err := cmd.RootCmd.Execute()
		if err != nil {
			helpFunc(nil, nil)
		}
	}
}

func createReadline() (l *readline.Instance, err error) {
	return readline.NewEx(&readline.Config{
		Prompt:          getUserPrompt(),
		AutoComplete:    readline.NewPrefixCompleter(readline.PcItemDynamic(listFuncNames())),
		InterruptPrompt: "^C",
		EOFPrompt:       "exit",
	})
}

func getUserPrompt() string {
	var user string

	if !stringIsEmpty(os.Getenv("USER")) {
		user = os.Getenv("USER")
	} else if !stringIsEmpty(os.Getenv("USERNAME")) {
		user = os.Getenv("USERNAME")
	} else {
		user = "unknown"
	}

	return fmt.Sprintf("%s@homehub: ", user)
}

func listFuncNames() func(string) []string {
	return func(s string) []string {
		return getFuncNames()
	}
}

func getFuncNames() []string {
	v := reflect.TypeOf(&homehub.Hub{})
	funcNames := make([]string, v.NumMethod())
	for i := 0; i < v.NumMethod(); i++ {
		funcNames[i] = v.Method(i).Name
	}
	return funcNames
}

func invokeMethod(methodName string) {
	m := reflect.ValueOf(hub).MethodByName(methodName)
	if m.IsValid() {
		if hub != nil {
			resp := m.Call(nil)
			result := resp[0].String()
			fmt.Println(result)
		} else {
			fmt.Println("homehub: You are not logged in. Use the Login command")
		}
	} else {
		fmt.Println("homehub: Command not found:", strconv.Quote(methodName))
	}
}

func stringIsEmpty(s string) bool {
	return len(strings.TrimSpace(s)) == 0
}

func doLogin(l *readline.Instance) *homehub.Hub {
	var URL string
	var username string
	var password []byte

	fmt.Print("Home hub URL: ")
	fmt.Scan(&URL)

	fmt.Print("Home hub user name: ")
	fmt.Scan(&username)

	password, _ = l.ReadPassword("Home hub password: ")

	hub := homehub.New(URL, username, string(password))
	success, _ := hub.Login()

	if !success {
		fmt.Println("Login failed")
		return nil
	}

	fmt.Println("Logged in as", username)

	return hub
}

func banner() {
	fmt.Println(" _   _                           _   _         _")
	fmt.Println("| | | |                         | | | |       | |")
	fmt.Println("| |_| |  ___   _ __ ___    ___  | |_| | _   _ | |__")
	fmt.Println("|  _  | / _ \\ | '_ ` _ \\  / _ \\ |  _  || | | || '_ \\")
	fmt.Println("| | | || (_) || | | | | ||  __/ | | | || |_| || |_) |")
	fmt.Println("\\_| |_/ \\___/ |_| |_| |_| \\___| \\_| |_/ \\__,_||_.__/")
	fmt.Printf("\n=====================================================\n\n")
}
<commit_msg>Handle function arguments  - Validate correct number of arguments are provided for functions. This closes #4  - Force login prompt instead of displaying message. This closed #5<commit_after>package main

import (
	"fmt"
	"io"
	"os"
	"reflect"
	"strconv"
	"strings"

	"github.com/chzyer/readline"
	"github.com/jamesnetherton/homehub-client"
	"github.com/spf13/cobra"
	"github.com/spf13/cobra/cobra/cmd"
)

var (
	hubURL   string
	userName string
	password string
	hub      *homehub.Hub
)

func main() {
	cmd.RootCmd.PersistentFlags().StringVarP(&hubURL, "huburl", "r", "http://192.168.1.254", "URL of the home hub router")
	cmd.RootCmd.PersistentFlags().StringVarP(&userName, "username", "u", "admin", "The hub router user name")
	cmd.RootCmd.PersistentFlags().StringVarP(&password, "password", "p", "", "The home hub router password")

	cmdHandler := func(cmd *cobra.Command, args []string) {
		if !stringIsEmpty(hubURL) && !stringIsEmpty(userName) && !stringIsEmpty(password) {
			hub = homehub.New(hubURL, userName, password)
			success, _ := hub.Login()

			if !success {
				fmt.Println("Login failed")
				return
			}

			invokeMethod(nil, cmd.Name(), args)
		} else {
			cmd.Usage()
		}
	}

	for _, funcName := range getFuncNames() {
		cmd.RootCmd.AddCommand(&cobra.Command{
			Use: funcName,
			Run: cmdHandler,
		})
	}

	helpFunc := func(cmd *cobra.Command, args []string) {
		fmt.Println("Usage:\n  homehub-cli [command] --huburl=<home hub url> --username=<home hub username> --password=<home hub password>")
		fmt.Println("\nCommands:\n ", strings.Join(getFuncNames(), "\n  "))
	}

	usageFunc := func(cmd *cobra.Command) error {
		fmt.Printf("Usage:\n  homehub-cli %s --huburl=<home hub url> --username=<home hub username> --password=<home hub password>\n", cmd.Name())
		return nil
	}

	cmd.RootCmd.SetHelpFunc(helpFunc)
	cmd.RootCmd.SetUsageFunc(usageFunc)
	cmd.RootCmd.SilenceErrors = true

	if len(os.Args[1:]) == 0 {
		banner()

		l, err := createReadline()
		if err != nil {
			panic(err)
		}
		defer l.Close()

		for {
			line, err := l.Readline()

			if err == readline.ErrInterrupt {
				if len(line) == 0 {
					break
				} else {
					continue
				}
			} else if err == io.EOF {
				break
			}

			line = strings.TrimSpace(line)
			if !stringIsEmpty(line) {
				if !strings.HasPrefix(line, "Login") {
					cmd := strings.Split(line, " ")
					methodName := cmd[0]
					args := append(cmd[:0], cmd[1:]...)
					invokeMethod(l, methodName, args)
				} else {
					hub = doLogin(l)
				}
			}
		}
	} else {
		err := cmd.RootCmd.Execute()
		if err != nil {
			helpFunc(nil, nil)
		}
	}
}

func createReadline() (l *readline.Instance, err error) {
	return readline.NewEx(&readline.Config{
		Prompt:          getUserPrompt(),
		AutoComplete:    readline.NewPrefixCompleter(readline.PcItemDynamic(listFuncNames())),
		InterruptPrompt: "^C",
		EOFPrompt:       "exit",
	})
}

func getUserPrompt() string {
	var user string

	if !stringIsEmpty(os.Getenv("USER")) {
		user = os.Getenv("USER")
	} else if !stringIsEmpty(os.Getenv("USERNAME")) {
		user = os.Getenv("USERNAME")
	} else {
		user = "unknown"
	}

	return fmt.Sprintf("%s@homehub: ", user)
}

func listFuncNames() func(string) []string {
	return func(s string) []string {
		return getFuncNames()
	}
}

func getFuncNames() []string {
	v := reflect.TypeOf(&homehub.Hub{})
	funcNames := make([]string, v.NumMethod())
	for i := 0; i < v.NumMethod(); i++ {
		funcNames[i] = v.Method(i).Name
	}
	return funcNames
}

func invokeMethod(l *readline.Instance, methodName string, args []string) {
	h := reflect.TypeOf(hub)
	m, found := h.MethodByName(methodName)
	if found {
		t := m.Func.Type()
		inputs := make([]reflect.Value, t.NumIn())

		if t.NumIn() > 0 {
			argOffset := 0
			if t.In(0).Kind().String() == "ptr" {
				argOffset = 1
			}

			if len(args) != t.NumIn()-argOffset {
				fmt.Printf("Wrong number of arguments for '%s'. Expected %d but got %d.\n", methodName, t.NumIn()-1, len(args))
				return
			}

			for i := argOffset; i < t.NumIn(); i++ {
				switch t.In(i).Kind().String() {
				case "bool":
					val, err := strconv.ParseBool(args[i-argOffset])
					if err == nil {
						inputs[i] = reflect.ValueOf(val)
					} else {
						fmt.Printf("Expected '%s' boolean function argument %d to be either true or false . But got '%s'.\n", methodName, i, args[i-argOffset])
						return
					}
					break
				case "int":
					val, err := strconv.Atoi(args[i-argOffset])
					if err == nil {
						inputs[i] = reflect.ValueOf(val)
					} else {
						fmt.Printf("Expected '%s' int function argument %d to be numeric. But got '%s'.\n", methodName, i, args[i-argOffset])
						return
					}
					break
				default:
					inputs[i] = reflect.ValueOf(args[i-argOffset])
				}
			}
		}

		if hub == nil {
			fmt.Printf("\nYou are not logged in. Please login...\n\n")
			hub = doLogin(l)
		}

		if hub != nil {
			inputs[0] = reflect.ValueOf(hub)
			resp := m.Func.Call(inputs)
			if t.NumOut() > 0 {
				result := resp[0].String()
				fmt.Println(result)
			}
		}
	} else {
		fmt.Println("homehub: Command not found:", strconv.Quote(methodName))
	}
}

func stringIsEmpty(s string) bool {
	return len(strings.TrimSpace(s)) == 0
}

func doLogin(l *readline.Instance) *homehub.Hub {
	var URL string
	var username string
	var password []byte

	fmt.Print("Home hub URL: ")
	fmt.Scan(&URL)

	fmt.Print("Home hub user name: ")
	fmt.Scan(&username)

	password, _ = l.ReadPassword("Home hub password: ")

	hub := homehub.New(URL, username, string(password))
	success, _ := hub.Login()

	if !success {
		fmt.Println("Login failed")
		return nil
	}

	fmt.Println("Logged in as", username)

	return hub
}

func banner() {
	fmt.Println(" _   _                           _   _         _")
	fmt.Println("| | | |                         | | | |       | |")
	fmt.Println("| |_| |  ___   _ __ ___    ___  | |_| | _   _ | |__")
	fmt.Println("|  _  | / _ \\ | '_ ` _ \\  / _ \\ |  _  || | | || '_ \\")
	fmt.Println("| | | || (_) || | | | | ||  __/ | | | || |_| || |_) |")
	fmt.Println("\\_| |_/ \\___/ |_| |_| |_| \\___| \\_| |_/ \\__,_||_.__/")
	fmt.Printf("\n=====================================================\n\n")
}
<|endoftext|>


<commit_before>package main

/*
 * A libjit wrapper for Golang
 *
 * Copyright (c) 2013-2014 Chanwit Kaewkasi
 * Suranaree University of Technology
 *
 */
import "fmt"
import . "github.com/chanwit/jit"

/*
extern int NativeMult(int a,int b);
*/
import "C"

//export NativeMult
func NativeMult(a, b C.int) C.int {
	fmt.Println(">>>>Test")
	return a * b
}

func main() {

	// Create a context to hold the JIT's primary state
	// defer to Destroy the context at the end of func main()
	ctx := NewContext()
	defer ctx.Destroy()

	// Lock the context while we build and compile the function
	ctx.BuildStart()

	// Create the function object
	// void foo(int x, int y, int* result) {
	//   *result = NativeMult(x, y);
	// }
	f := ctx.NewFunction(Void(), []Type{Int(), Int(), VoidPtr()})

	// Construct the function body
	x, y, result := f.Param3()

	// This is native call
	sig := NewSignature(Int(), []Type{Int(), Int()})
	res := f.CallNative("NativeMult", C.NativeMult, sig, x, y)
	f.Store(x, res)
	f.StoreRelative(result, 0, x)

	// Compile the function
	f.Compile()

	// Dump the result to standard output
	f.Dump("foo")

	// Unlock the context
	ctx.BuildEnd()

	// Execute the function
	var r int = 0
	f.Run(3, 5, &r)
	fmt.Println(r)
}
<commit_msg>dump uncompiled<commit_after>package main

/*
 * A libjit wrapper for Golang
 *
 * Copyright (c) 2013-2014 Chanwit Kaewkasi
 * Suranaree University of Technology
 *
 */
import "fmt"
import . "github.com/chanwit/jit"

/*
extern int NativeMult(int a,int b);
*/
import "C"

//export NativeMult
func NativeMult(a, b C.int) C.int {
	fmt.Println(">>>>Test")
	return a * b
}

func main() {

	// Create a context to hold the JIT's primary state
	// defer to Destroy the context at the end of func main()
	ctx := NewContext()
	defer ctx.Destroy()

	// Lock the context while we build and compile the function
	ctx.BuildStart()

	// Create the function object
	// void foo(int x, int y, int* result) {
	//   *result = NativeMult(x, y);
	// }
	f := ctx.NewFunction(Void(), []Type{Int(), Int(), VoidPtr()})

	// Construct the function body
	x, y, result := f.Param3()

	// This is native call
	sig := NewSignature(Int(), []Type{Int(), Int()})
	res := f.CallNative("NativeMult", C.NativeMult, sig, x, y)
	f.Store(x, res)
	f.StoreRelative(result, 0, x)

	f.Dump("foo [uncompiled]")

	// Compile the function
	f.Compile()

	// Dump the result to standard output
	f.Dump("foo [compiled]")

	// Unlock the context
	ctx.BuildEnd()

	// Execute the function
	var r int = 0
	f.Run(3, 5, &r)
	fmt.Println(r)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/dsvensson/go-xmmsclient/xmmsclient"
	"strings"
	"time"
)

func playlistChanges(client *xmmsclient.Client) {
	bcast := client.BroadcastPlaylistChanged()
	for {
		value, err := bcast.Next()
		if err != nil {
			fmt.Println(err)
			return
		}
		fmt.Println(value)
	}
}

func repeat(client *xmmsclient.Client) {
	for {
		value, err := client.PlaylistListEntries(xmmsclient.ActivePlaylist)
		if err != nil {
			fmt.Println("Fail!", err)
			return
		}
		for position, mid := range value {
			propDict, err := client.MedialibGetInfo(mid)
			if err != nil {
				fmt.Println("Fail!", err)
				return
			}

			dict, err := xmmsclient.PropDictToDictDefault(propDict)
			if err != nil {
				return
			}

			fmt.Printf("repeat(): [%2d] %s // %s // %s\n",
				position, dict["artist"], dict["album"], dict["title"])
		}
		time.Sleep(time.Millisecond * 1500)
	}
}

func main() {
	client := xmmsclient.NewClient("hello-from-go")

	client.Dial("localhost:xmms2")

	go repeat(client)
	go playlistChanges(client)

	time.Sleep(time.Millisecond * 5)

	value, err := client.CollectionList(xmmsclient.NamespacePlaylists)
	if err != nil {
		fmt.Println(err)
		return
	}

	for index, name := range value {
		if !strings.HasPrefix(name, "_") {
			fmt.Printf("  main(): [%2v] %v::%v\n", index, xmmsclient.NamespacePlaylists, name)
		}
	}

	time.Sleep(time.Second * 20)
	fmt.Println(" close():")
	client.Close()
	fmt.Println(" sleep():")
	time.Sleep(time.Second * 1)
}
<commit_msg>Improve error logging in test client.<commit_after>package main

import (
	"fmt"
	"github.com/dsvensson/go-xmmsclient/xmmsclient"
	"strings"
	"time"
)

func playlistChanges(client *xmmsclient.Client) {
	bcast := client.BroadcastPlaylistChanged()
	for {
		value, err := bcast.Next()
		if err != nil {
			fmt.Println("Error(PlaylistChanged):", err)
			return
		}
		fmt.Println(value)
	}
}

func repeat(client *xmmsclient.Client) {
	for {
		value, err := client.PlaylistListEntries(xmmsclient.ActivePlaylist)
		if err != nil {
			fmt.Println("Error(PlaylistListEntries):", err)
			return
		}
		for position, mid := range value {
			propDict, err := client.MedialibGetInfo(mid)
			if err != nil {
				fmt.Println("Error(GetInfo):", err)
				return
			}

			dict, err := xmmsclient.PropDictToDictDefault(propDict)
			if err != nil {
				fmt.Println("Error(PropDict->Dict):", err)
				return
			}

			fmt.Printf("repeat(): [%2d] %s // %s // %s\n",
				position, dict["artist"], dict["album"], dict["title"])
		}
		time.Sleep(time.Millisecond * 1500)
	}
}

func main() {
	client := xmmsclient.NewClient("hello-from-go")

	err := client.Dial("localhost:xmms2")
	if err != nil {
		fmt.Println("Error(Dial):", err)
		return
	}

	go repeat(client)
	go playlistChanges(client)

	time.Sleep(time.Millisecond * 5)

	value, err := client.CollectionList(xmmsclient.NamespacePlaylists)
	if err != nil {
		fmt.Println("Error(CollectionList):", err)
		return
	}

	for index, name := range value {
		if !strings.HasPrefix(name, "_") {
			fmt.Printf("  main(): [%2v] %v::%v\n", index, xmmsclient.NamespacePlaylists, name)
		}
	}

	time.Sleep(time.Second * 20)
	fmt.Println(" close():")
	client.Close()
	fmt.Println(" sleep():")
	time.Sleep(time.Second * 1)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"math/rand"
	"net/http"
	"time"

	"github.com/graphql-go/graphql"
)

type Todo struct {
	ID   string `json:"id"`
	Text string `json:"text"`
	Done bool   `json:"done"`
}

var TodoList []Todo
var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")

func RandStringRunes(n int) string {
	b := make([]rune, n)
	for i := range b {
		b[i] = letterRunes[rand.Intn(len(letterRunes))]
	}
	return string(b)
}

func init() {
	todo1 := Todo{ID: "a", Text: "A todo not to forget", Done: false}
	todo2 := Todo{ID: "b", Text: "This is the most important", Done: false}
	todo3 := Todo{ID: "c", Text: "Please do this or else", Done: false}
	TodoList = append(TodoList, todo1, todo2, todo3)

	rand.Seed(time.Now().UnixNano())
}

// define custom GraphQL ObjectType `todoType` for our Golang struct `Todo`
// Note that
// - the fields in our todoType maps with the json tags for the fields in our struct
// - the field type matches the field type in our struct
var todoType = graphql.NewObject(graphql.ObjectConfig{
	Name: "Todo",
	Fields: graphql.Fields{
		"id": &graphql.Field{
			Type: graphql.String,
		},
		"text": &graphql.Field{
			Type: graphql.String,
		},
		"done": &graphql.Field{
			Type: graphql.Boolean,
		},
	},
})

// root mutation
var rootMutation = graphql.NewObject(graphql.ObjectConfig{
	Name: "RootMutation",
	Fields: graphql.Fields{
		/*
		   curl -g 'http://localhost:8080/graphql?query=mutation+_{createTodo(text:"My+new+todo"){id,text,done}}'
		*/
		"createTodo": &graphql.Field{
			Type:        todoType, // the return type for this field
			Description: "Create new todo",
			Args: graphql.FieldConfigArgument{
				"text": &graphql.ArgumentConfig{
					Type: graphql.NewNonNull(graphql.String),
				},
			},
			Resolve: func(params graphql.ResolveParams) (interface{}, error) {

				// marshall and cast the argument value
				text, _ := params.Args["text"].(string)

				// figure out new id
				newId := RandStringRunes(8)

				// perform mutation operation here
				// for e.g. create a Todo and save to DB.
				newTodo := Todo{
					ID:   newId,
					Text: text,
					Done: false,
				}

				TodoList = append(TodoList, newTodo)

				// return the new Todo object that we supposedly save to DB
				// Note here that
				// - we are returning a `Todo` struct instance here
				// - we previously specified the return Type to be `todoType`
				// - `Todo` struct maps to `todoType`, as defined in `todoType` ObjectConfig`
				return newTodo, nil
			},
		},

		/*
			curl -g 'http://localhost:8080/graphql?query=mutation+_{updateTodo(id:"a",done:true){id,text,done}}'
		*/
		"updateTodo": &graphql.Field{
			Type:        todoType, // the return type for this field
			Description: "Update existing todo, mark it done or not done",
			Args: graphql.FieldConfigArgument{
				"done": &graphql.ArgumentConfig{
					Type: graphql.Boolean,
				},
				"id": &graphql.ArgumentConfig{
					Type: graphql.NewNonNull(graphql.String),
				},
			},
			Resolve: func(params graphql.ResolveParams) (interface{}, error) {

				// marshall and cast the argument value
				done, _ := params.Args["done"].(bool)
				id, _ := params.Args["id"].(string)
				affectedTodo := Todo{}

				// Search list for todo with id and change the done variable
				for i := 0; i < len(TodoList); i++ {
					if TodoList[i].ID == id {
						TodoList[i].Done = done
						// Assign updated todo so we can return it
						affectedTodo = TodoList[i]
						break
					}
				}

				// Return affected todo
				return affectedTodo, nil
			},
		},
	},
})

// root query
// we just define a trivial example here, since root query is required.
// Test with curl
// curl -g 'http://localhost:8080/graphql?query={lastTodo{id,text,done}}'
var rootQuery = graphql.NewObject(graphql.ObjectConfig{
	Name: "RootQuery",
	Fields: graphql.Fields{

		/*
		   curl -g 'http://localhost:8080/graphql?query={todo(id:"b"){id,text,done}}'
		*/
		"todo": &graphql.Field{
			Type: todoType,
			Args: graphql.FieldConfigArgument{
				"id": &graphql.ArgumentConfig{
					Type: graphql.String,
				},
			},
			Resolve: func(params graphql.ResolveParams) (interface{}, error) {

				idQuery, isOK := params.Args["id"].(string)
				if isOK {
					// Search for el with id
					for _, todo := range TodoList {
						if todo.ID == idQuery {
							return todo, nil
						}
					}
				}

				return Todo{}, nil
			},
		},

		"lastTodo": &graphql.Field{
			Type:        todoType,
			Description: "Last todo added",
			Resolve: func(params graphql.ResolveParams) (interface{}, error) {
				return TodoList[len(TodoList)-1], nil
			},
		},

		/*
		   curl -g 'http://localhost:8080/graphql?query={todoList{id,text,done}}'
		*/
		"todoList": &graphql.Field{
			Type:        graphql.NewList(todoType),
			Description: "List of todos",
			Resolve: func(p graphql.ResolveParams) (interface{}, error) {
				return TodoList, nil
			},
		},
	},
})

// define schema, with our rootQuery and rootMutation
var schema, _ = graphql.NewSchema(graphql.SchemaConfig{
	Query:    rootQuery,
	Mutation: rootMutation,
})

func executeQuery(query string, schema graphql.Schema) *graphql.Result {
	result := graphql.Do(graphql.Params{
		Schema:        schema,
		RequestString: query,
	})
	if len(result.Errors) > 0 {
		fmt.Printf("wrong result, unexpected errors: %v", result.Errors)
	}
	return result
}

func main() {
	http.HandleFunc("/graphql", func(w http.ResponseWriter, r *http.Request) {
		result := executeQuery(r.URL.Query()["query"][0], schema)
		json.NewEncoder(w).Encode(result)
	})

	// Serve static files
	fs := http.FileServer(http.Dir("static"))
	http.Handle("/", fs)

	// Display some basic instructions
	fmt.Println("Now server is running on port 8080")
	fmt.Println("Get single todo: curl -g 'http://localhost:8080/graphql?query={todo(id:\"b\"){id,text,done}}'")
	fmt.Println("Create new todo: curl -g 'http://localhost:8080/graphql?query=mutation+_{createTodo(text:\"My+new+todo\"){id,text,done}}'")
	fmt.Println("Load todo list: curl -g 'http://localhost:8080/graphql?query={todoList{id,text,done}}'")
	fmt.Println("Access the web app via browser at 'http://localhost:8080'")

	http.ListenAndServe(":8080", nil)
}
<commit_msg>Add `todo` query description<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"math/rand"
	"net/http"
	"time"

	"github.com/graphql-go/graphql"
)

type Todo struct {
	ID   string `json:"id"`
	Text string `json:"text"`
	Done bool   `json:"done"`
}

var TodoList []Todo
var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")

func RandStringRunes(n int) string {
	b := make([]rune, n)
	for i := range b {
		b[i] = letterRunes[rand.Intn(len(letterRunes))]
	}
	return string(b)
}

func init() {
	todo1 := Todo{ID: "a", Text: "A todo not to forget", Done: false}
	todo2 := Todo{ID: "b", Text: "This is the most important", Done: false}
	todo3 := Todo{ID: "c", Text: "Please do this or else", Done: false}
	TodoList = append(TodoList, todo1, todo2, todo3)

	rand.Seed(time.Now().UnixNano())
}

// define custom GraphQL ObjectType `todoType` for our Golang struct `Todo`
// Note that
// - the fields in our todoType maps with the json tags for the fields in our struct
// - the field type matches the field type in our struct
var todoType = graphql.NewObject(graphql.ObjectConfig{
	Name: "Todo",
	Fields: graphql.Fields{
		"id": &graphql.Field{
			Type: graphql.String,
		},
		"text": &graphql.Field{
			Type: graphql.String,
		},
		"done": &graphql.Field{
			Type: graphql.Boolean,
		},
	},
})

// root mutation
var rootMutation = graphql.NewObject(graphql.ObjectConfig{
	Name: "RootMutation",
	Fields: graphql.Fields{
		/*
		   curl -g 'http://localhost:8080/graphql?query=mutation+_{createTodo(text:"My+new+todo"){id,text,done}}'
		*/
		"createTodo": &graphql.Field{
			Type:        todoType, // the return type for this field
			Description: "Create new todo",
			Args: graphql.FieldConfigArgument{
				"text": &graphql.ArgumentConfig{
					Type: graphql.NewNonNull(graphql.String),
				},
			},
			Resolve: func(params graphql.ResolveParams) (interface{}, error) {

				// marshall and cast the argument value
				text, _ := params.Args["text"].(string)

				// figure out new id
				newId := RandStringRunes(8)

				// perform mutation operation here
				// for e.g. create a Todo and save to DB.
				newTodo := Todo{
					ID:   newId,
					Text: text,
					Done: false,
				}

				TodoList = append(TodoList, newTodo)

				// return the new Todo object that we supposedly save to DB
				// Note here that
				// - we are returning a `Todo` struct instance here
				// - we previously specified the return Type to be `todoType`
				// - `Todo` struct maps to `todoType`, as defined in `todoType` ObjectConfig`
				return newTodo, nil
			},
		},

		/*
			curl -g 'http://localhost:8080/graphql?query=mutation+_{updateTodo(id:"a",done:true){id,text,done}}'
		*/
		"updateTodo": &graphql.Field{
			Type:        todoType, // the return type for this field
			Description: "Update existing todo, mark it done or not done",
			Args: graphql.FieldConfigArgument{
				"done": &graphql.ArgumentConfig{
					Type: graphql.Boolean,
				},
				"id": &graphql.ArgumentConfig{
					Type: graphql.NewNonNull(graphql.String),
				},
			},
			Resolve: func(params graphql.ResolveParams) (interface{}, error) {

				// marshall and cast the argument value
				done, _ := params.Args["done"].(bool)
				id, _ := params.Args["id"].(string)
				affectedTodo := Todo{}

				// Search list for todo with id and change the done variable
				for i := 0; i < len(TodoList); i++ {
					if TodoList[i].ID == id {
						TodoList[i].Done = done
						// Assign updated todo so we can return it
						affectedTodo = TodoList[i]
						break
					}
				}

				// Return affected todo
				return affectedTodo, nil
			},
		},
	},
})

// root query
// we just define a trivial example here, since root query is required.
// Test with curl
// curl -g 'http://localhost:8080/graphql?query={lastTodo{id,text,done}}'
var rootQuery = graphql.NewObject(graphql.ObjectConfig{
	Name: "RootQuery",
	Fields: graphql.Fields{

		/*
		   curl -g 'http://localhost:8080/graphql?query={todo(id:"b"){id,text,done}}'
		*/
		"todo": &graphql.Field{
			Type:        todoType,
			Description: "Get single todo",
			Args: graphql.FieldConfigArgument{
				"id": &graphql.ArgumentConfig{
					Type: graphql.String,
				},
			},
			Resolve: func(params graphql.ResolveParams) (interface{}, error) {

				idQuery, isOK := params.Args["id"].(string)
				if isOK {
					// Search for el with id
					for _, todo := range TodoList {
						if todo.ID == idQuery {
							return todo, nil
						}
					}
				}

				return Todo{}, nil
			},
		},

		"lastTodo": &graphql.Field{
			Type:        todoType,
			Description: "Last todo added",
			Resolve: func(params graphql.ResolveParams) (interface{}, error) {
				return TodoList[len(TodoList)-1], nil
			},
		},

		/*
		   curl -g 'http://localhost:8080/graphql?query={todoList{id,text,done}}'
		*/
		"todoList": &graphql.Field{
			Type:        graphql.NewList(todoType),
			Description: "List of todos",
			Resolve: func(p graphql.ResolveParams) (interface{}, error) {
				return TodoList, nil
			},
		},
	},
})

// define schema, with our rootQuery and rootMutation
var schema, _ = graphql.NewSchema(graphql.SchemaConfig{
	Query:    rootQuery,
	Mutation: rootMutation,
})

func executeQuery(query string, schema graphql.Schema) *graphql.Result {
	result := graphql.Do(graphql.Params{
		Schema:        schema,
		RequestString: query,
	})
	if len(result.Errors) > 0 {
		fmt.Printf("wrong result, unexpected errors: %v", result.Errors)
	}
	return result
}

func main() {
	http.HandleFunc("/graphql", func(w http.ResponseWriter, r *http.Request) {
		result := executeQuery(r.URL.Query()["query"][0], schema)
		json.NewEncoder(w).Encode(result)
	})

	// Serve static files
	fs := http.FileServer(http.Dir("static"))
	http.Handle("/", fs)

	// Display some basic instructions
	fmt.Println("Now server is running on port 8080")
	fmt.Println("Get single todo: curl -g 'http://localhost:8080/graphql?query={todo(id:\"b\"){id,text,done}}'")
	fmt.Println("Create new todo: curl -g 'http://localhost:8080/graphql?query=mutation+_{createTodo(text:\"My+new+todo\"){id,text,done}}'")
	fmt.Println("Load todo list: curl -g 'http://localhost:8080/graphql?query={todoList{id,text,done}}'")
	fmt.Println("Access the web app via browser at 'http://localhost:8080'")

	http.ListenAndServe(":8080", nil)
}
<|endoftext|>


<commit_before>// Copyright (C) 2019-2021, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package rpcchainvm

import (
	"errors"
	"io/ioutil"
	"log"

	"google.golang.org/grpc"

	"github.com/hashicorp/go-hclog"
	"github.com/hashicorp/go-plugin"

	"github.com/ava-labs/avalanchego/snow"
	"github.com/ava-labs/avalanchego/utils/math"
	"github.com/ava-labs/avalanchego/utils/subprocess"
)

var (
	errWrongVM = errors.New("wrong vm type")

	serverOptions = []grpc.ServerOption{
		grpc.MaxRecvMsgSize(math.MaxInt),
		grpc.MaxSendMsgSize(math.MaxInt),
	}
	dialOptions = []grpc.DialOption{
		grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(math.MaxInt)),
		grpc.WithDefaultCallOptions(grpc.MaxCallSendMsgSize(math.MaxInt)),
	}

	_ Factory = &factory{}
)

type Factory interface {
	// New returns an instance of a virtual machine.
	New(*snow.Context) (interface{}, error)
}

type factory struct {
	path string
}

func NewFactory(path string) Factory {
	return &factory{
		path: path,
	}
}

func (f *factory) New(ctx *snow.Context) (interface{}, error) {
	config := &plugin.ClientConfig{
		HandshakeConfig: Handshake,
		Plugins:         PluginMap,
		Cmd:             subprocess.New(f.path),
		AllowedProtocols: []plugin.Protocol{
			plugin.ProtocolGRPC,
		},
		// We kill this client by calling kill() when the chain running this VM
		// shuts down. However, there are some cases where the VM's Shutdown
		// method is not called. Namely, if:
		// 1) The node shuts down after the client is created but before the
		//    chain is registered with the message router.
		// 2) The chain doesn't handle a shutdown message before the node times
		//    out on the chain's shutdown and dies, leaving the shutdown message
		//    unhandled.
		// We set managed to true so that we can call plugin.CleanupClients on
		// node shutdown to ensure every plugin subprocess is killed.
		Managed:         true,
		GRPCDialOptions: dialOptions,
	}
	if ctx != nil {
		log.SetOutput(ctx.Log)
		config.Stderr = ctx.Log
		config.Logger = hclog.New(&hclog.LoggerOptions{
			Output: ctx.Log,
			Level:  hclog.Info,
		})
	} else {
		log.SetOutput(ioutil.Discard)
		config.Stderr = ioutil.Discard
		config.Logger = hclog.New(&hclog.LoggerOptions{
			Output: ioutil.Discard,
		})
	}
	client := plugin.NewClient(config)

	rpcClient, err := client.Client()
	if err != nil {
		client.Kill()
		return nil, err
	}

	raw, err := rpcClient.Dispense("vm")
	if err != nil {
		client.Kill()
		return nil, err
	}

	vm, ok := raw.(*VMClient)
	if !ok {
		client.Kill()
		return nil, errWrongVM
	}

	vm.SetProcess(client)
	vm.ctx = ctx
	return vm, nil
}
<commit_msg>vms/rpcchainvm: add plugin name to errors (#1225)<commit_after>// Copyright (C) 2019-2021, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package rpcchainvm

import (
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"path/filepath"

	"google.golang.org/grpc"

	"github.com/hashicorp/go-hclog"
	"github.com/hashicorp/go-plugin"

	"github.com/ava-labs/avalanchego/snow"
	"github.com/ava-labs/avalanchego/utils/math"
	"github.com/ava-labs/avalanchego/utils/subprocess"
)

var (
	errWrongVM = errors.New("wrong vm type")

	serverOptions = []grpc.ServerOption{
		grpc.MaxRecvMsgSize(math.MaxInt),
		grpc.MaxSendMsgSize(math.MaxInt),
	}
	dialOptions = []grpc.DialOption{
		grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(math.MaxInt)),
		grpc.WithDefaultCallOptions(grpc.MaxCallSendMsgSize(math.MaxInt)),
	}

	_ Factory = &factory{}
)

type Factory interface {
	// New returns an instance of a virtual machine.
	New(*snow.Context) (interface{}, error)
}

type factory struct {
	path string
}

func NewFactory(path string) Factory {
	return &factory{
		path: path,
	}
}

func (f *factory) New(ctx *snow.Context) (interface{}, error) {
	config := &plugin.ClientConfig{
		HandshakeConfig: Handshake,
		Plugins:         PluginMap,
		Cmd:             subprocess.New(f.path),
		AllowedProtocols: []plugin.Protocol{
			plugin.ProtocolGRPC,
		},
		// We kill this client by calling kill() when the chain running this VM
		// shuts down. However, there are some cases where the VM's Shutdown
		// method is not called. Namely, if:
		// 1) The node shuts down after the client is created but before the
		//    chain is registered with the message router.
		// 2) The chain doesn't handle a shutdown message before the node times
		//    out on the chain's shutdown and dies, leaving the shutdown message
		//    unhandled.
		// We set managed to true so that we can call plugin.CleanupClients on
		// node shutdown to ensure every plugin subprocess is killed.
		Managed:         true,
		GRPCDialOptions: dialOptions,
	}
	if ctx != nil {
		log.SetOutput(ctx.Log)
		config.Stderr = ctx.Log
		config.Logger = hclog.New(&hclog.LoggerOptions{
			Output: ctx.Log,
			Level:  hclog.Info,
		})
	} else {
		log.SetOutput(ioutil.Discard)
		config.Stderr = ioutil.Discard
		config.Logger = hclog.New(&hclog.LoggerOptions{
			Output: ioutil.Discard,
		})
	}
	client := plugin.NewClient(config)

	pluginName := filepath.Base(f.path)
	pluginErr := func(err error) error {
		return fmt.Errorf("plugin: %q: %w", pluginName, err)
	}

	rpcClient, err := client.Client()
	if err != nil {
		client.Kill()
		return nil, pluginErr(err)
	}

	raw, err := rpcClient.Dispense("vm")
	if err != nil {
		client.Kill()
		return nil, pluginErr(err)
	}

	vm, ok := raw.(*VMClient)
	if !ok {
		client.Kill()
		return nil, pluginErr(errWrongVM)
	}

	vm.SetProcess(client)
	vm.ctx = ctx
	return vm, nil
}
<|endoftext|>


<commit_before>package volman_test

import (
	"os"
	"path"

	"code.cloudfoundry.org/inigo/helpers"
	"code.cloudfoundry.org/localdriver"
	"code.cloudfoundry.org/volman"

	"github.com/jeffpak/local-node-plugin/node"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/tedsuo/ifrit/ginkgomon"
)

var _ = Describe("Given volman and a local-node-plugin", func() {
	var (
		volumeName          string
		csiVolume           string
		csiMountRootDir     string
		expectedMountPath   string
		volumeConfig        map[string]interface{}
		mountResponse       volman.MountResponse
		listDriversResponse volman.ListDriversResponse
		err                 error
	)

	It("should eventually discover the plugin", func() {
		Eventually(func() bool {
			listDriversResponse, err = volmanClient.ListDrivers(logger)
			Expect(err).NotTo(HaveOccurred())
			infos := listDriversResponse.Drivers
			for _, info := range infos {
				if info.Name == node.NODE_PLUGIN_ID {
					return true
				}
			}
			return false
		}).Should(Equal(true))
	})

	Context("when running mount and unmount", func() {
		BeforeEach(func() {
			volumeName = "someVolume"
			csiVolume = "csiVolume"
			csiMountRootDir = "local-node-plugin-mount"
			volumeConfig = map[string]interface{}{"id": csiVolume, "attributes": map[string]string{}}
			expectedMountPath = path.Join(componentMaker.VolmanDriverConfigDir(), csiMountRootDir, node.NODE_PLUGIN_ID, volumeName)
		})

		JustBeforeEach(func() {
			mountResponse, err = volmanClient.Mount(logger, node.NODE_PLUGIN_ID, volumeName, volumeConfig)
		})

		Context("when volumeConfig doesn't have any attributes", func() {
			BeforeEach(func() {
				volumeConfig = map[string]interface{}{"id": csiVolume}
			})

			It("should be able to mount volume", func() {
				Expect(err).NotTo(HaveOccurred())
				mountPoint := mountResponse.Path
				Expect(mountPoint).To(Equal(expectedMountPath))
				Expect(expectedMountPath).To(BeAnExistingFile())
			})

			It("should be able to unmount volume", func() {
				err = volmanClient.Unmount(logger, node.NODE_PLUGIN_ID, volumeName)
				Expect(err).NotTo(HaveOccurred())
				Expect(expectedMountPath).NotTo(BeAnExistingFile())
			})

		})

		It("should be able to mount volume", func() {
			Expect(err).NotTo(HaveOccurred())
			mountPoint := mountResponse.Path
			Expect(mountPoint).To(Equal(expectedMountPath))
			Expect(expectedMountPath).To(BeAnExistingFile())
		})

		It("should be able to unmount volume", func() {
			err = volmanClient.Unmount(logger, node.NODE_PLUGIN_ID, volumeName)
			Expect(err).NotTo(HaveOccurred())
			Expect(expectedMountPath).NotTo(BeAnExistingFile())
		})

	})

	Context("when volman client restarted", func() {
		BeforeEach(func() {
			volumeName = "someVolume"
			csiVolume = "csiVolume"
			volumeConfig = map[string]interface{}{"id": csiVolume, "attributes": map[string]string{}}
			expectedMountPath = path.Join(componentMaker.VolmanDriverConfigDir(), localdriver.MountsRootDir, volumeName)
		})

		JustBeforeEach(func() {
			mountResponse, err = volmanClient.Mount(logger, "localdriver", volumeName, volumeConfig)
			helpers.StopProcesses(driverSyncerProcess)
		})

		It("should purge existing mount points", func() {
			Eventually(func() bool {
				_, err = os.Stat(expectedMountPath)
				return os.IsNotExist(err)
			}).Should(Equal(false))

			volmanClient, driverSyncer = componentMaker.VolmanClient(logger)
			driverSyncerProcess = ginkgomon.Invoke(driverSyncer)

			Eventually(func() bool {
				_, err = os.Stat(expectedMountPath)
				return os.IsNotExist(err)
			}).Should(Equal(true))
		})
	})

})
<commit_msg>update the expected mount path for csi plugin<commit_after>package volman_test

import (
	"os"
	"path"

	"code.cloudfoundry.org/inigo/helpers"
	"code.cloudfoundry.org/localdriver"
	"code.cloudfoundry.org/volman"

	"github.com/jeffpak/local-node-plugin/node"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/tedsuo/ifrit/ginkgomon"
)

var _ = Describe("Given volman and a local-node-plugin", func() {
	var (
		volumeName          string
		csiVolume           string
		csiMountRootDir     string
		expectedMountPath   string
		volumeConfig        map[string]interface{}
		mountResponse       volman.MountResponse
		listDriversResponse volman.ListDriversResponse
		err                 error
	)

	It("should eventually discover the plugin", func() {
		Eventually(func() bool {
			listDriversResponse, err = volmanClient.ListDrivers(logger)
			Expect(err).NotTo(HaveOccurred())
			infos := listDriversResponse.Drivers
			for _, info := range infos {
				if info.Name == node.NODE_PLUGIN_ID {
					return true
				}
			}
			return false
		}).Should(Equal(true))
	})

	Context("when running mount and unmount", func() {
		BeforeEach(func() {
			volumeName = "someVolume"
			csiVolume = "csiVolume"
			csiMountRootDir = "local-node-plugin-mount"
			volumeConfig = map[string]interface{}{"id": csiVolume, "attributes": map[string]string{}}
			expectedMountPath = path.Join(componentMaker.VolmanDriverConfigDir(), csiMountRootDir, "mounts", node.NODE_PLUGIN_ID, volumeName)
		})

		JustBeforeEach(func() {
			mountResponse, err = volmanClient.Mount(logger, node.NODE_PLUGIN_ID, volumeName, volumeConfig)
		})

		Context("when volumeConfig doesn't have any attributes", func() {
			BeforeEach(func() {
				volumeConfig = map[string]interface{}{"id": csiVolume}
			})

			It("should be able to mount volume", func() {
				Expect(err).NotTo(HaveOccurred())
				mountPoint := mountResponse.Path
				Expect(mountPoint).To(Equal(expectedMountPath))
				Expect(expectedMountPath).To(BeAnExistingFile())
			})

			It("should be able to unmount volume", func() {
				err = volmanClient.Unmount(logger, node.NODE_PLUGIN_ID, volumeName)
				Expect(err).NotTo(HaveOccurred())
				Expect(expectedMountPath).NotTo(BeAnExistingFile())
			})

		})

		It("should be able to mount volume", func() {
			Expect(err).NotTo(HaveOccurred())
			mountPoint := mountResponse.Path
			Expect(mountPoint).To(Equal(expectedMountPath))
			Expect(expectedMountPath).To(BeAnExistingFile())
		})

		It("should be able to unmount volume", func() {
			err = volmanClient.Unmount(logger, node.NODE_PLUGIN_ID, volumeName)
			Expect(err).NotTo(HaveOccurred())
			Expect(expectedMountPath).NotTo(BeAnExistingFile())
		})

	})

	Context("when volman client restarted", func() {
		BeforeEach(func() {
			volumeName = "someVolume"
			csiVolume = "csiVolume"
			volumeConfig = map[string]interface{}{"id": csiVolume, "attributes": map[string]string{}}
			expectedMountPath = path.Join(componentMaker.VolmanDriverConfigDir(), localdriver.MountsRootDir, volumeName)
		})

		JustBeforeEach(func() {
			mountResponse, err = volmanClient.Mount(logger, "localdriver", volumeName, volumeConfig)
			helpers.StopProcesses(driverSyncerProcess)
		})

		It("should purge existing mount points", func() {
			Eventually(func() bool {
				_, err = os.Stat(expectedMountPath)
				return os.IsNotExist(err)
			}).Should(Equal(false))

			volmanClient, driverSyncer = componentMaker.VolmanClient(logger)
			driverSyncerProcess = ginkgomon.Invoke(driverSyncer)

			Eventually(func() bool {
				_, err = os.Stat(expectedMountPath)
				return os.IsNotExist(err)
			}).Should(Equal(true))
		})
	})

})
<|endoftext|>


<commit_before>package broadcastwriter

import (
	"bytes"
	"io"
	"sync"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/docker/docker/pkg/jsonlog"
	"github.com/docker/docker/pkg/timeutils"
)

// BroadcastWriter accumulate multiple io.WriteCloser by stream.
type BroadcastWriter struct {
	sync.Mutex
	buf      *bytes.Buffer
	jsLogBuf *bytes.Buffer
	streams  map[string](map[io.WriteCloser]struct{})
}

// AddWriter adds new io.WriteCloser for stream.
// If stream is "", then all writes proceed as is. Otherwise every line from
// input will be packed to serialized jsonlog.JSONLog.
func (w *BroadcastWriter) AddWriter(writer io.WriteCloser, stream string) {
	w.Lock()
	if _, ok := w.streams[stream]; !ok {
		w.streams[stream] = make(map[io.WriteCloser]struct{})
	}
	w.streams[stream][writer] = struct{}{}
	w.Unlock()
}

// Write writes bytes to all writers. Failed writers will be evicted during
// this call.
func (w *BroadcastWriter) Write(p []byte) (n int, err error) {
	var timestamp string
	created := time.Now().UTC()
	w.Lock()
	if writers, ok := w.streams[""]; ok {
		for sw := range writers {
			if n, err := sw.Write(p); err != nil || n != len(p) {
				// On error, evict the writer
				delete(writers, sw)
			}
		}
	}
	if w.jsLogBuf == nil {
		w.jsLogBuf = new(bytes.Buffer)
		w.jsLogBuf.Grow(1024)
	}
	w.buf.Write(p)
	for {
		if n := w.buf.Len(); n == 0 {
			break
		}
		i := bytes.IndexByte(w.buf.Bytes(), '\n')
		if i < 0 {
			break
		}
		lineBytes := w.buf.Next(i + 1)
		if timestamp == "" {
			timestamp, err = timeutils.FastMarshalJSON(created)
			if err != nil {
				continue
			}
		}

		for stream, writers := range w.streams {
			if stream == "" {
				continue
			}
			jsonLog := jsonlog.JSONLogBytes{Log: lineBytes, Stream: stream, Created: timestamp}
			err = jsonLog.MarshalJSONBuf(w.jsLogBuf)
			if err != nil {
				log.Errorf("Error making JSON log line: %s", err)
				continue
			}
			w.jsLogBuf.WriteByte('\n')
			b := w.jsLogBuf.Bytes()
			for sw := range writers {
				if _, err := sw.Write(b); err != nil {
					delete(writers, sw)
				}
			}
		}
		w.jsLogBuf.Reset()
	}
	w.jsLogBuf.Reset()
	w.Unlock()
	return len(p), nil
}

// Clean closes and removes all writers. Last non-eol-terminated part of data
// will be saved.
func (w *BroadcastWriter) Clean() error {
	w.Lock()
	for _, writers := range w.streams {
		for w := range writers {
			w.Close()
		}
	}
	w.streams = make(map[string](map[io.WriteCloser]struct{}))
	w.Unlock()
	return nil
}

func New() *BroadcastWriter {
	return &BroadcastWriter{
		streams: make(map[string](map[io.WriteCloser]struct{})),
		buf:     bytes.NewBuffer(nil),
	}
}
<commit_msg>Skip heavy operations if there is no jsonlog writers<commit_after>package broadcastwriter

import (
	"bytes"
	"io"
	"sync"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/docker/docker/pkg/jsonlog"
	"github.com/docker/docker/pkg/timeutils"
)

// BroadcastWriter accumulate multiple io.WriteCloser by stream.
type BroadcastWriter struct {
	sync.Mutex
	buf      *bytes.Buffer
	jsLogBuf *bytes.Buffer
	streams  map[string](map[io.WriteCloser]struct{})
}

// AddWriter adds new io.WriteCloser for stream.
// If stream is "", then all writes proceed as is. Otherwise every line from
// input will be packed to serialized jsonlog.JSONLog.
func (w *BroadcastWriter) AddWriter(writer io.WriteCloser, stream string) {
	w.Lock()
	if _, ok := w.streams[stream]; !ok {
		w.streams[stream] = make(map[io.WriteCloser]struct{})
	}
	w.streams[stream][writer] = struct{}{}
	w.Unlock()
}

// Write writes bytes to all writers. Failed writers will be evicted during
// this call.
func (w *BroadcastWriter) Write(p []byte) (n int, err error) {
	w.Lock()
	if writers, ok := w.streams[""]; ok {
		for sw := range writers {
			if n, err := sw.Write(p); err != nil || n != len(p) {
				// On error, evict the writer
				delete(writers, sw)
			}
		}
		// exit if there is no more writers
		if len(w.streams) == 1 {
			w.buf.Reset()
			w.Unlock()
			return len(p), nil
		}
	}
	if w.jsLogBuf == nil {
		w.jsLogBuf = new(bytes.Buffer)
		w.jsLogBuf.Grow(1024)
	}
	var timestamp string
	created := time.Now().UTC()
	w.buf.Write(p)
	for {
		if n := w.buf.Len(); n == 0 {
			break
		}
		i := bytes.IndexByte(w.buf.Bytes(), '\n')
		if i < 0 {
			break
		}
		lineBytes := w.buf.Next(i + 1)
		if timestamp == "" {
			timestamp, err = timeutils.FastMarshalJSON(created)
			if err != nil {
				continue
			}
		}

		for stream, writers := range w.streams {
			if stream == "" {
				continue
			}
			jsonLog := jsonlog.JSONLogBytes{Log: lineBytes, Stream: stream, Created: timestamp}
			err = jsonLog.MarshalJSONBuf(w.jsLogBuf)
			if err != nil {
				log.Errorf("Error making JSON log line: %s", err)
				continue
			}
			w.jsLogBuf.WriteByte('\n')
			b := w.jsLogBuf.Bytes()
			for sw := range writers {
				if _, err := sw.Write(b); err != nil {
					delete(writers, sw)
				}
			}
		}
		w.jsLogBuf.Reset()
	}
	w.jsLogBuf.Reset()
	w.Unlock()
	return len(p), nil
}

// Clean closes and removes all writers. Last non-eol-terminated part of data
// will be saved.
func (w *BroadcastWriter) Clean() error {
	w.Lock()
	for _, writers := range w.streams {
		for w := range writers {
			w.Close()
		}
	}
	w.streams = make(map[string](map[io.WriteCloser]struct{}))
	w.Unlock()
	return nil
}

func New() *BroadcastWriter {
	return &BroadcastWriter{
		streams: make(map[string](map[io.WriteCloser]struct{})),
		buf:     bytes.NewBuffer(nil),
	}
}
<|endoftext|>