<commit_before>package torus

import (
	"errors"
	"io"
	"os"
	"sync"
	"time"

	"golang.org/x/net/context"

	"github.com/coreos/pkg/capnslog"
	"github.com/prometheus/client_golang/prometheus"

	"github.com/coreos/torus/models"
)

var (
	promOpenINodes = prometheus.NewGaugeVec(prometheus.GaugeOpts{
		Name: "torus_server_open_inodes",
		Help: "Number of open inodes reported on last update to mds",
	}, []string{"volume"})
	promOpenFiles = prometheus.NewGaugeVec(prometheus.GaugeOpts{
		Name: "torus_server_open_files",
		Help: "Number of open files",
	}, []string{"volume"})
	promFileSyncs = prometheus.NewCounterVec(prometheus.CounterOpts{
		Name: "torus_server_file_syncs",
		Help: "Number of times a file has been synced on this server",
	}, []string{"volume"})
	promFileChangedSyncs = prometheus.NewCounterVec(prometheus.CounterOpts{
		Name: "torus_server_file_changed_syncs",
		Help: "Number of times a file has been synced on this server, and the file has changed underneath it",
	}, []string{"volume"})
	promFileWrittenBytes = prometheus.NewCounterVec(prometheus.CounterOpts{
		Name: "torus_server_file_written_bytes",
		Help: "Number of bytes written to a file on this server",
	}, []string{"volume"})
	promFileBlockRead = prometheus.NewHistogram(prometheus.HistogramOpts{
		Name:    "torus_server_file_block_read_us",
		Help:    "Histogram of ms taken to read a block through the layers and into the file abstraction",
		Buckets: prometheus.ExponentialBuckets(50.0, 2, 20),
	})
	promFileBlockWrite = prometheus.NewHistogram(prometheus.HistogramOpts{
		Name:    "torus_server_file_block_write_us",
		Help:    "Histogram of ms taken to write a block through the layers and into the file abstraction",
		Buckets: prometheus.ExponentialBuckets(50.0, 2, 20),
	})
)

func init() {
	prometheus.MustRegister(promOpenINodes)
	prometheus.MustRegister(promOpenFiles)
	prometheus.MustRegister(promFileSyncs)
	prometheus.MustRegister(promFileChangedSyncs)
	prometheus.MustRegister(promFileWrittenBytes)
	prometheus.MustRegister(promFileBlockRead)
	prometheus.MustRegister(promFileBlockWrite)
}

type File struct {
	// globals
	mut      sync.RWMutex
	srv      *Server
	blkSize  int64
	offset   int64
	ReadOnly bool

	// file metadata
	volume   *models.Volume
	inode    *models.INode
	blocks   Blockset
	replaces uint64
	changed  map[string]bool
	cache    fileCache

	writeINodeRef INodeRef
	writeOpen     bool
}

func (f *File) WriteOpen() bool {
	return f.writeOpen
}

func (f *File) Replaces() uint64 {
	return f.replaces
}

func (s *Server) CreateFile(volume *models.Volume, inode *models.INode, blocks Blockset) (*File, error) {
	md := s.MDS.GlobalMetadata()
	clog.Tracef("Creating File For Inode %d:%d", inode.Volume, inode.INode)
	return &File{
		volume:  volume,
		inode:   inode,
		srv:     s,
		blocks:  blocks,
		blkSize: int64(md.BlockSize),
		cache:   newSingleBlockCache(blocks, md.BlockSize),
	}, nil
}

func (f *File) openWrite() error {
	if f.ReadOnly {
		return ErrLocked
	}
	if f.writeOpen {
		return nil
	}
	vid := VolumeID(f.volume.Id)
	newINode, err := f.srv.MDS.CommitINodeIndex(vid)
	if err != nil {
		return err
	}
	f.writeINodeRef = NewINodeRef(VolumeID(vid), newINode)
	if f.inode != nil {
		f.replaces = f.inode.INode
		f.inode.INode = uint64(newINode)
	}
	f.writeOpen = true
	f.cache.newINode(f.writeINodeRef)
	return nil
}

func (f *File) writeToBlock(i, from, to int, data []byte) (int, error) {
	return f.cache.writeToBlock(f.getContext(), i, from, to, data)
}

func (f *File) getContext() context.Context {
	return f.srv.getContext()
}

func (f *File) Write(b []byte) (n int, err error) {
	n, err = f.WriteAt(b, f.offset)
	f.offset += int64(n)
	return
}

func (f *File) WriteAt(b []byte, off int64) (n int, err error) {
	f.mut.Lock()
	defer f.mut.Unlock()
	err = f.openWrite()
	if err != nil {
		return 0, err
	}

	if clog.LevelAt(capnslog.TRACE) {
		clog.Trace("begin write: offset ", off, " size ", len(b))
	}
	toWrite := len(b)

	defer func() {
		if off > int64(f.inode.Filesize) {
			clog.Tracef("updating filesize: %d", off)
			f.inode.Filesize = uint64(off)
		}
	}()

	// Write the front matter, which may dangle from a byte offset
	blkIndex := int(off / f.blkSize)

	if f.blocks.Length()+1 < blkIndex {
		if clog.LevelAt(capnslog.DEBUG) {
			clog.Debug("begin write: offset ", off, " size ", len(b))
			clog.Debug("end of file ", f.blocks.Length(), " blkIndex ", blkIndex)
		}
		promFileWrittenBytes.WithLabelValues(f.volume.Name).Add(float64(n))
		err := f.Truncate(off)
		if err != nil {
			return n, err
		}
		//return n, errors.New("Can't write past the end of a file")
	}

	blkOff := off - int64(int(f.blkSize)*blkIndex)
	if blkOff != 0 {
		frontlen := int(f.blkSize - blkOff)
		if frontlen > toWrite {
			frontlen = toWrite
		}
		wrote, err := f.writeToBlock(blkIndex, int(blkOff), int(blkOff)+frontlen, b[:frontlen])
		clog.Tracef("head writing block at index %d, inoderef %s", blkIndex, f.writeINodeRef)
		if err != nil {
			return n, err
		} else if wrote != frontlen {
			promFileWrittenBytes.WithLabelValues(f.volume.Name).Add(float64(n))
			return n, errors.New("Couldn't write all of the first block at the offset")
		}
		b = b[frontlen:]
		n += wrote
		off += int64(wrote)
	}

	toWrite = len(b)
	if toWrite == 0 {
		// We're done
		promFileWrittenBytes.WithLabelValues(f.volume.Name).Add(float64(n))
		return n, nil
	}

	// Bulk Write! We'd rather be here.
	if off%f.blkSize != 0 {
		panic("Offset not equal to a block boundary")
	}

	for toWrite >= int(f.blkSize) {
		blkIndex := int(off / f.blkSize)
		if clog.LevelAt(capnslog.TRACE) {
			clog.Tracef("bulk writing block at index %d, inoderef %s", blkIndex, f.writeINodeRef)
		}
		start := time.Now()
		err = f.blocks.PutBlock(f.getContext(), f.writeINodeRef, blkIndex, b[:f.blkSize])
		if err != nil {
			promFileWrittenBytes.WithLabelValues(f.volume.Name).Add(float64(n))
			return n, err
		}
		delta := time.Now().Sub(start)
		promFileBlockWrite.Observe(float64(delta.Nanoseconds()) / 1000)
		b = b[f.blkSize:]
		n += int(f.blkSize)
		off += int64(f.blkSize)
		toWrite = len(b)
	}

	if toWrite == 0 {
		// We're done
		promFileWrittenBytes.WithLabelValues(f.volume.Name).Add(float64(n))
		return n, nil
	}

	// Trailing matter. This sucks too.
	if off%f.blkSize != 0 {
		panic("Offset not equal to a block boundary after bulk")
	}
	blkIndex = int(off / f.blkSize)
	wrote, err := f.writeToBlock(blkIndex, 0, toWrite, b)
	if clog.LevelAt(capnslog.TRACE) {
		clog.Tracef("tail writing block at index %d, inoderef %s", blkIndex, f.writeINodeRef)
	}
	if err != nil {
		promFileWrittenBytes.WithLabelValues(f.volume.Name).Add(float64(n))
		return n, err
	} else if wrote != toWrite {
		promFileWrittenBytes.WithLabelValues(f.volume.Name).Add(float64(n))
		return n, errors.New("Couldn't write all of the last block")
	}
	n += wrote
	off += int64(wrote)
	promFileWrittenBytes.WithLabelValues(f.volume.Name).Add(float64(n))
	return n, nil
}

func (f *File) Read(b []byte) (n int, err error) {
	n, err = f.ReadAt(b, f.offset)
	f.offset += int64(n)
	return
}

func (f *File) ReadAt(b []byte, off int64) (n int, ferr error) {
	f.mut.RLock()
	defer f.mut.RUnlock()
	toRead := len(b)
	if clog.LevelAt(capnslog.TRACE) {
		clog.Tracef("begin read @ %x of size %d", off, toRead)
	}
	n = 0
	if int64(toRead)+off > int64(f.inode.Filesize) {
		toRead = int(int64(f.inode.Filesize) - off)
		ferr = io.EOF
		clog.Tracef("read is longer than file")
	}
	for toRead > n {
		blkIndex := int(off / f.blkSize)
		blkOff := off - int64(int(f.blkSize)*blkIndex)
		if clog.LevelAt(capnslog.TRACE) {
			clog.Tracef("getting block index %d", blkIndex)
		}
		blk, err := f.cache.getBlock(f.getContext(), blkIndex)
		if err != nil {
			return n, err
		}
		thisRead := f.blkSize - blkOff
		if int64(toRead-n) < thisRead {
			thisRead = int64(toRead - n)
		}
		count := copy(b[n:], blk[blkOff:blkOff+thisRead])
		n += count
		off += int64(count)
	}
	if toRead != n {
		//panic("Read more than n bytes?")
	}
	return n, ferr
}

func (f *File) Seek(offset int64, whence int) (int64, error) {
	// TODO(mischief): validate offset
	switch whence {
	case os.SEEK_SET:
		f.offset = offset
	case os.SEEK_CUR:
		f.offset += offset
	case os.SEEK_END:
		//f.offset = int64(f.inode.Filesize) - offset
		fallthrough
	default:
		return 0, errors.New("invalid whence")
	}

	return offset, nil
}

func (f *File) Close() error {
	if f == nil {
		return ErrInvalid
	}
	promOpenFiles.WithLabelValues(f.volume.Name).Dec()
	return nil
}

func (f *File) Truncate(size int64) error {
	err := f.openWrite()
	if err != nil {
		return err
	}
	nBlocks := (size / f.blkSize)
	if size%f.blkSize != 0 {
		nBlocks++
	}
	clog.Tracef("truncate to %d %d", size, nBlocks)
	f.blocks.Truncate(int(nBlocks), uint64(f.blkSize))
	f.inode.Filesize = uint64(size)
	return nil
}

// Trim zeroes data in the middle of a file.
func (f *File) Trim(offset, length int64) error {
	clog.Debugf("trimming %d %d", offset, length)
	err := f.openWrite()
	if err != nil {
		return err
	}
	// find the block edges
	blkFrom := offset / f.blkSize
	if offset%f.blkSize != 0 {
		blkFrom += 1
	}
	blkTo := (offset + length) / f.blkSize
	return f.blocks.Trim(int(blkFrom), int(blkTo))
}

func (f *File) SyncAllWrites() (INodeRef, error) {
	err := f.SyncBlocks()
	if err != nil {
		return ZeroINode(), err
	}
	return f.SyncINode(f.getContext())
}

func (f *File) SyncINode(ctx context.Context) (INodeRef, error) {
	ref := f.writeINodeRef
	blkdata, err := MarshalBlocksetToProto(f.blocks)
	if err != nil {
		clog.Error("sync: couldn't marshal proto")
		return ZeroINode(), err
	}
	f.inode.Blocks = blkdata
	if f.inode.Volume != f.volume.Id {
		panic("mismatched volume and inode volume")
	}
	err = f.srv.INodes.WriteINode(ctx, ref, f.inode)
	if err != nil {
		return ZeroINode(), err
	}
	f.writeOpen = false
	return ref, nil
}

func (f *File) SyncBlocks() error {
	err := f.cache.sync(f.getContext())
	if err != nil {
		clog.Error("sync: couldn't sync block")
		return err
	}
	return f.srv.Blocks.Flush()
}

func (f *File) Size() uint64 {
	return f.inode.Filesize
}
<commit_msg>file: tiny: output trace log before call writeToBlock<commit_after>package torus

import (
	"errors"
	"io"
	"os"
	"sync"
	"time"

	"golang.org/x/net/context"

	"github.com/coreos/pkg/capnslog"
	"github.com/prometheus/client_golang/prometheus"

	"github.com/coreos/torus/models"
)

var (
	promOpenINodes = prometheus.NewGaugeVec(prometheus.GaugeOpts{
		Name: "torus_server_open_inodes",
		Help: "Number of open inodes reported on last update to mds",
	}, []string{"volume"})
	promOpenFiles = prometheus.NewGaugeVec(prometheus.GaugeOpts{
		Name: "torus_server_open_files",
		Help: "Number of open files",
	}, []string{"volume"})
	promFileSyncs = prometheus.NewCounterVec(prometheus.CounterOpts{
		Name: "torus_server_file_syncs",
		Help: "Number of times a file has been synced on this server",
	}, []string{"volume"})
	promFileChangedSyncs = prometheus.NewCounterVec(prometheus.CounterOpts{
		Name: "torus_server_file_changed_syncs",
		Help: "Number of times a file has been synced on this server, and the file has changed underneath it",
	}, []string{"volume"})
	promFileWrittenBytes = prometheus.NewCounterVec(prometheus.CounterOpts{
		Name: "torus_server_file_written_bytes",
		Help: "Number of bytes written to a file on this server",
	}, []string{"volume"})
	promFileBlockRead = prometheus.NewHistogram(prometheus.HistogramOpts{
		Name:    "torus_server_file_block_read_us",
		Help:    "Histogram of ms taken to read a block through the layers and into the file abstraction",
		Buckets: prometheus.ExponentialBuckets(50.0, 2, 20),
	})
	promFileBlockWrite = prometheus.NewHistogram(prometheus.HistogramOpts{
		Name:    "torus_server_file_block_write_us",
		Help:    "Histogram of ms taken to write a block through the layers and into the file abstraction",
		Buckets: prometheus.ExponentialBuckets(50.0, 2, 20),
	})
)

func init() {
	prometheus.MustRegister(promOpenINodes)
	prometheus.MustRegister(promOpenFiles)
	prometheus.MustRegister(promFileSyncs)
	prometheus.MustRegister(promFileChangedSyncs)
	prometheus.MustRegister(promFileWrittenBytes)
	prometheus.MustRegister(promFileBlockRead)
	prometheus.MustRegister(promFileBlockWrite)
}

type File struct {
	// globals
	mut      sync.RWMutex
	srv      *Server
	blkSize  int64
	offset   int64
	ReadOnly bool

	// file metadata
	volume   *models.Volume
	inode    *models.INode
	blocks   Blockset
	replaces uint64
	changed  map[string]bool
	cache    fileCache

	writeINodeRef INodeRef
	writeOpen     bool
}

func (f *File) WriteOpen() bool {
	return f.writeOpen
}

func (f *File) Replaces() uint64 {
	return f.replaces
}

func (s *Server) CreateFile(volume *models.Volume, inode *models.INode, blocks Blockset) (*File, error) {
	md := s.MDS.GlobalMetadata()
	clog.Tracef("Creating File For Inode %d:%d", inode.Volume, inode.INode)
	return &File{
		volume:  volume,
		inode:   inode,
		srv:     s,
		blocks:  blocks,
		blkSize: int64(md.BlockSize),
		cache:   newSingleBlockCache(blocks, md.BlockSize),
	}, nil
}

func (f *File) openWrite() error {
	if f.ReadOnly {
		return ErrLocked
	}
	if f.writeOpen {
		return nil
	}
	vid := VolumeID(f.volume.Id)
	newINode, err := f.srv.MDS.CommitINodeIndex(vid)
	if err != nil {
		return err
	}
	f.writeINodeRef = NewINodeRef(VolumeID(vid), newINode)
	if f.inode != nil {
		f.replaces = f.inode.INode
		f.inode.INode = uint64(newINode)
	}
	f.writeOpen = true
	f.cache.newINode(f.writeINodeRef)
	return nil
}

func (f *File) writeToBlock(i, from, to int, data []byte) (int, error) {
	return f.cache.writeToBlock(f.getContext(), i, from, to, data)
}

func (f *File) getContext() context.Context {
	return f.srv.getContext()
}

func (f *File) Write(b []byte) (n int, err error) {
	n, err = f.WriteAt(b, f.offset)
	f.offset += int64(n)
	return
}

func (f *File) WriteAt(b []byte, off int64) (n int, err error) {
	f.mut.Lock()
	defer f.mut.Unlock()
	err = f.openWrite()
	if err != nil {
		return 0, err
	}

	if clog.LevelAt(capnslog.TRACE) {
		clog.Trace("begin write: offset ", off, " size ", len(b))
	}
	toWrite := len(b)

	defer func() {
		if off > int64(f.inode.Filesize) {
			clog.Tracef("updating filesize: %d", off)
			f.inode.Filesize = uint64(off)
		}
	}()

	// Write the front matter, which may dangle from a byte offset
	blkIndex := int(off / f.blkSize)

	if f.blocks.Length()+1 < blkIndex {
		if clog.LevelAt(capnslog.DEBUG) {
			clog.Debug("begin write: offset ", off, " size ", len(b))
			clog.Debug("end of file ", f.blocks.Length(), " blkIndex ", blkIndex)
		}
		promFileWrittenBytes.WithLabelValues(f.volume.Name).Add(float64(n))
		err := f.Truncate(off)
		if err != nil {
			return n, err
		}
		//return n, errors.New("Can't write past the end of a file")
	}

	blkOff := off - int64(int(f.blkSize)*blkIndex)
	if blkOff != 0 {
		frontlen := int(f.blkSize - blkOff)
		if frontlen > toWrite {
			frontlen = toWrite
		}
		clog.Tracef("head writing block at index %d, inoderef %s", blkIndex, f.writeINodeRef)
		wrote, err := f.writeToBlock(blkIndex, int(blkOff), int(blkOff)+frontlen, b[:frontlen])
		if err != nil {
			return n, err
		} else if wrote != frontlen {
			promFileWrittenBytes.WithLabelValues(f.volume.Name).Add(float64(n))
			return n, errors.New("Couldn't write all of the first block at the offset")
		}
		b = b[frontlen:]
		n += wrote
		off += int64(wrote)
	}

	toWrite = len(b)
	if toWrite == 0 {
		// We're done
		promFileWrittenBytes.WithLabelValues(f.volume.Name).Add(float64(n))
		return n, nil
	}

	// Bulk Write! We'd rather be here.
	if off%f.blkSize != 0 {
		panic("Offset not equal to a block boundary")
	}

	for toWrite >= int(f.blkSize) {
		blkIndex := int(off / f.blkSize)
		if clog.LevelAt(capnslog.TRACE) {
			clog.Tracef("bulk writing block at index %d, inoderef %s", blkIndex, f.writeINodeRef)
		}
		start := time.Now()
		err = f.blocks.PutBlock(f.getContext(), f.writeINodeRef, blkIndex, b[:f.blkSize])
		if err != nil {
			promFileWrittenBytes.WithLabelValues(f.volume.Name).Add(float64(n))
			return n, err
		}
		delta := time.Now().Sub(start)
		promFileBlockWrite.Observe(float64(delta.Nanoseconds()) / 1000)
		b = b[f.blkSize:]
		n += int(f.blkSize)
		off += int64(f.blkSize)
		toWrite = len(b)
	}

	if toWrite == 0 {
		// We're done
		promFileWrittenBytes.WithLabelValues(f.volume.Name).Add(float64(n))
		return n, nil
	}

	// Trailing matter. This sucks too.
	if off%f.blkSize != 0 {
		panic("Offset not equal to a block boundary after bulk")
	}
	blkIndex = int(off / f.blkSize)
	if clog.LevelAt(capnslog.TRACE) {
		clog.Tracef("tail writing block at index %d, inoderef %s", blkIndex, f.writeINodeRef)
	}
	wrote, err := f.writeToBlock(blkIndex, 0, toWrite, b)
	if err != nil {
		promFileWrittenBytes.WithLabelValues(f.volume.Name).Add(float64(n))
		return n, err
	} else if wrote != toWrite {
		promFileWrittenBytes.WithLabelValues(f.volume.Name).Add(float64(n))
		return n, errors.New("Couldn't write all of the last block")
	}
	n += wrote
	off += int64(wrote)
	promFileWrittenBytes.WithLabelValues(f.volume.Name).Add(float64(n))
	return n, nil
}

func (f *File) Read(b []byte) (n int, err error) {
	n, err = f.ReadAt(b, f.offset)
	f.offset += int64(n)
	return
}

func (f *File) ReadAt(b []byte, off int64) (n int, ferr error) {
	f.mut.RLock()
	defer f.mut.RUnlock()
	toRead := len(b)
	if clog.LevelAt(capnslog.TRACE) {
		clog.Tracef("begin read @ %x of size %d", off, toRead)
	}
	n = 0
	if int64(toRead)+off > int64(f.inode.Filesize) {
		toRead = int(int64(f.inode.Filesize) - off)
		ferr = io.EOF
		clog.Tracef("read is longer than file")
	}
	for toRead > n {
		blkIndex := int(off / f.blkSize)
		blkOff := off - int64(int(f.blkSize)*blkIndex)
		if clog.LevelAt(capnslog.TRACE) {
			clog.Tracef("getting block index %d", blkIndex)
		}
		blk, err := f.cache.getBlock(f.getContext(), blkIndex)
		if err != nil {
			return n, err
		}
		thisRead := f.blkSize - blkOff
		if int64(toRead-n) < thisRead {
			thisRead = int64(toRead - n)
		}
		count := copy(b[n:], blk[blkOff:blkOff+thisRead])
		n += count
		off += int64(count)
	}
	if toRead != n {
		//panic("Read more than n bytes?")
	}
	return n, ferr
}

func (f *File) Seek(offset int64, whence int) (int64, error) {
	// TODO(mischief): validate offset
	switch whence {
	case os.SEEK_SET:
		f.offset = offset
	case os.SEEK_CUR:
		f.offset += offset
	case os.SEEK_END:
		//f.offset = int64(f.inode.Filesize) - offset
		fallthrough
	default:
		return 0, errors.New("invalid whence")
	}

	return offset, nil
}

func (f *File) Close() error {
	if f == nil {
		return ErrInvalid
	}
	promOpenFiles.WithLabelValues(f.volume.Name).Dec()
	return nil
}

func (f *File) Truncate(size int64) error {
	err := f.openWrite()
	if err != nil {
		return err
	}
	nBlocks := (size / f.blkSize)
	if size%f.blkSize != 0 {
		nBlocks++
	}
	clog.Tracef("truncate to %d %d", size, nBlocks)
	f.blocks.Truncate(int(nBlocks), uint64(f.blkSize))
	f.inode.Filesize = uint64(size)
	return nil
}

// Trim zeroes data in the middle of a file.
func (f *File) Trim(offset, length int64) error {
	clog.Debugf("trimming %d %d", offset, length)
	err := f.openWrite()
	if err != nil {
		return err
	}
	// find the block edges
	blkFrom := offset / f.blkSize
	if offset%f.blkSize != 0 {
		blkFrom += 1
	}
	blkTo := (offset + length) / f.blkSize
	return f.blocks.Trim(int(blkFrom), int(blkTo))
}

func (f *File) SyncAllWrites() (INodeRef, error) {
	err := f.SyncBlocks()
	if err != nil {
		return ZeroINode(), err
	}
	return f.SyncINode(f.getContext())
}

func (f *File) SyncINode(ctx context.Context) (INodeRef, error) {
	ref := f.writeINodeRef
	blkdata, err := MarshalBlocksetToProto(f.blocks)
	if err != nil {
		clog.Error("sync: couldn't marshal proto")
		return ZeroINode(), err
	}
	f.inode.Blocks = blkdata
	if f.inode.Volume != f.volume.Id {
		panic("mismatched volume and inode volume")
	}
	err = f.srv.INodes.WriteINode(ctx, ref, f.inode)
	if err != nil {
		return ZeroINode(), err
	}
	f.writeOpen = false
	return ref, nil
}

func (f *File) SyncBlocks() error {
	err := f.cache.sync(f.getContext())
	if err != nil {
		clog.Error("sync: couldn't sync block")
		return err
	}
	return f.srv.Blocks.Flush()
}

func (f *File) Size() uint64 {
	return f.inode.Filesize
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"os"
	"path"
	"runtime"

	. "github.com/fuzzy/gocolor"
	"github.com/kisielk/whisper-go/whisper"
	"github.com/urfave/cli"
)

func isDir(p string) bool {
	f, e := os.Stat(p)
	if e != nil {
		return false
	}
	return f.IsDir()
}

func chkErr(e error) bool {
	if e != nil {
		fmt.Printf("%s: %s\n", String("ERROR").Red().Bold(), e)
		return false
	} else {
		return true
	}
}

func backfillFile(s string, d string) bool {
	// Open our filehandles
	srcDb, srcErr := whisper.Open(s)
	chkErr(srcErr)
	dstDb, dstErr := whisper.Open(d)
	chkErr(dstErr)
	// Defer their closings
	defer srcDb.Close()
	defer dstDb.Close()

	// Now for a series of checks, first to ensure that both
	// files have the same number of archives in them.
	if srcDb.Header.Metadata.ArchiveCount != dstDb.Header.Metadata.ArchiveCount {
		fmt.Printf("%s: The files have a mismatched set of archives.\n", String("ERROR").Red().Bold())
		return false
	}

	// Now we'll start processing the archives, checking as we go to see if they are matched.
	// that way we at least fill in what we can, possibly....
	for i, a := range srcDb.Header.Archives {
		// The offset
		if a.Offset == dstDb.Header.Archives[i].Offset {
			// and the number of points
			if a.Points == dstDb.Header.Archives[i].Points {
				// and finally the interval
				if a.SecondsPerPoint == dstDb.Header.Archives[i].SecondsPerPoint {
					// ok, now let's get rolling through the archives
					fmt.Println("WE ARE GO, I REPEAT, WE ARE FUCKING GO!")
					sp, se := srcDb.DumpArchive(i)
					if se != nil {
						fmt.Printf("%s: %s\n", String("ERROR").Red().Bold(), se)
						os.Exit(1)
					}
					dp, de := dstDb.DumpArchive(i)
					if de != nil {
						fmt.Printf("%s: %s\n", String("ERROR").Red().Bold(), de)
						os.Exit(1)
					}
					for idx := 0; idx < len(sp); idx++ {
						if sp[idx].Timestamp != 0 && sp[idx].Value != 0 {
							if dp[idx].Timestamp == 0 || dp[idx].Value == 0 {
								fmt.Printf("SRC: %s %d %f\n", sp[idx].Time(), sp[idx].Timestamp, sp[idx].Value)
								fmt.Printf("DST: %s %d %f\n", dp[idx].Time(), dp[idx].Timestamp, dp[idx].Value)
							}
						}
					}
				}
			}
		}
	}
	return true
}

func Filler(c *cli.Context) error {
	if len(c.Args()) == 2 {
		args := c.Args()
		if isDir(args[0]) && isDir(args[1]) {
			e := fmt.Sprintf("%s: Dir comparison not complete yet", String("ERROR").Red().Bold())
			fmt.Println(e)
			return errors.New(e)
		} else {
			if !backfillFile(args[0], args[1]) {
				e := fmt.Sprintf("%s: There has been an error.", String("ERROR").Red().Bold())
				fmt.Println(e)
				return errors.New(e)
			}
		}
	} else {
		var e string
		if !c.Bool("c") {
			e = fmt.Sprintf("%s: Wrong number of paramters given.\n%s: Try '%s help fill' for more information",
				String("ERROR").Red().Bold(),
				String("ERROR").Red().Bold(),
				path.Base(os.Args[0]))
		} else {
			e = fmt.Sprintf("ERROR: Wrong number of parameters given.\nERROR: Try '%s help fill' for more information.",
				path.Base(os.Args[0]))
		}
		fmt.Println(e)
		return errors.New(e)
	}
	return nil
}

func init() {
	Commands = append(Commands, cli.Command{
		Name:        "fill",
		Aliases:     []string{"f"},
		Usage:       "Backfill datapoints in the dst(file|dir) from the src(file|dir)",
		Description: "Backfill datapoints in the dst(file|dir) from the src(file|dir)",
		ArgsUsage:   "<src(File|Dir)> <dst(File|Dir)>",
		Flags: []cli.Flag{
			cli.IntFlag{
				Name:  "j",
				Usage: "Number of workers (for directory recursion)",
				Value: runtime.GOMAXPROCS(0),
			},
			cli.BoolFlag{Name: "c", Usage: "Prevent colors from being used"},
		},
		SkipFlagParsing: false,
		HideHelp:        false,
		Hidden:          false,
		Action:          Filler,
	})
}
<commit_msg>just a quick fix, there is no error return here, so exiting is our easiest, safest route<commit_after>package main

import (
	"errors"
	"fmt"
	"os"
	"path"
	"runtime"

	. "github.com/fuzzy/gocolor"
	"github.com/kisielk/whisper-go/whisper"
	"github.com/urfave/cli"
)

func isDir(p string) bool {
	f, e := os.Stat(p)
	if e != nil {
		return false
	}
	return f.IsDir()
}

func chkErr(e error) bool {
	if e != nil {
		fmt.Printf("%s: %s\n", String("ERROR").Red().Bold(), e)
		return false
	} else {
		return true
	}
}

func backfillFile(s string, d string) bool {
	// Open our filehandles
	srcDb, srcErr := whisper.Open(s)
	dstDb, dstErr := whisper.Open(d)
	if !chkErr(srcErr) || !chkErr(dstErr) {
		os.Exit(1)
	}
	// Defer their closings
	defer srcDb.Close()
	defer dstDb.Close()

	// Now for a series of checks, first to ensure that both
	// files have the same number of archives in them.
	if srcDb.Header.Metadata.ArchiveCount != dstDb.Header.Metadata.ArchiveCount {
		fmt.Printf("%s: The files have a mismatched set of archives.\n", String("ERROR").Red().Bold())
		return false
	}

	// Now we'll start processing the archives, checking as we go to see if they are matched.
	// that way we at least fill in what we can, possibly....
	for i, a := range srcDb.Header.Archives {
		// The offset
		if a.Offset == dstDb.Header.Archives[i].Offset {
			// and the number of points
			if a.Points == dstDb.Header.Archives[i].Points {
				// and finally the interval
				if a.SecondsPerPoint == dstDb.Header.Archives[i].SecondsPerPoint {
					// ok, now let's get rolling through the archives
					fmt.Println("WE ARE GO, I REPEAT, WE ARE FUCKING GO!")
					sp, se := srcDb.DumpArchive(i)
					if se != nil {
						fmt.Printf("%s: %s\n", String("ERROR").Red().Bold(), se)
						os.Exit(1)
					}
					dp, de := dstDb.DumpArchive(i)
					if de != nil {
						fmt.Printf("%s: %s\n", String("ERROR").Red().Bold(), de)
						os.Exit(1)
					}
					for idx := 0; idx < len(sp); idx++ {
						if sp[idx].Timestamp != 0 && sp[idx].Value != 0 {
							if dp[idx].Timestamp == 0 || dp[idx].Value == 0 {
								fmt.Printf("SRC: %s %d %f\n", sp[idx].Time(), sp[idx].Timestamp, sp[idx].Value)
								fmt.Printf("DST: %s %d %f\n", dp[idx].Time(), dp[idx].Timestamp, dp[idx].Value)
							}
						}
					}
				}
			}
		}
	}
	return true
}

func Filler(c *cli.Context) error {
	if len(c.Args()) == 2 {
		args := c.Args()
		if isDir(args[0]) && isDir(args[1]) {
			e := fmt.Sprintf("%s: Dir comparison not complete yet", String("ERROR").Red().Bold())
			fmt.Println(e)
			return errors.New(e)
		} else {
			if !backfillFile(args[0], args[1]) {
				e := fmt.Sprintf("%s: There has been an error.", String("ERROR").Red().Bold())
				fmt.Println(e)
				return errors.New(e)
			}
		}
	} else {
		var e string
		if !c.Bool("c") {
			e = fmt.Sprintf("%s: Wrong number of paramters given.\n%s: Try '%s help fill' for more information",
				String("ERROR").Red().Bold(),
				String("ERROR").Red().Bold(),
				path.Base(os.Args[0]))
		} else {
			e = fmt.Sprintf("ERROR: Wrong number of parameters given.\nERROR: Try '%s help fill' for more information.",
				path.Base(os.Args[0]))
		}
		fmt.Println(e)
		return errors.New(e)
	}
	return nil
}

func init() {
	Commands = append(Commands, cli.Command{
		Name:        "fill",
		Aliases:     []string{"f"},
		Usage:       "Backfill datapoints in the dst(file|dir) from the src(file|dir)",
		Description: "Backfill datapoints in the dst(file|dir) from the src(file|dir)",
		ArgsUsage:   "<src(File|Dir)> <dst(File|Dir)>",
		Flags: []cli.Flag{
			cli.IntFlag{
				Name:  "j",
				Usage: "Number of workers (for directory recursion)",
				Value: runtime.GOMAXPROCS(0),
			},
			cli.BoolFlag{Name: "c", Usage: "Prevent colors from being used"},
		},
		SkipFlagParsing: false,
		HideHelp:        false,
		Hidden:          false,
		Action:          Filler,
	})
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net/http"
	"strconv"
	"time"

	"github.com/boltdb/bolt"
	"github.com/labstack/echo"
	"github.com/labstack/echo/middleware"
)

var saveSuccess = `
<meta http-equiv="Refresh" content="5; url=/" />

You have Successfully RSVP'd.  Thank you.  You will now be Redirected.

`

func echoServer() {
	e := echo.New()
	e.Use(middleware.Logger())
	e.Post("/rsvp", requestAddRsvp)

	admin := e.Group("/rsvp")
	admin.Use(middleware.BasicAuth(checkAuth))
	admin.Get("/list", requestListRsvp)
	admin.Get("/backup", requestBoltBackup)

	e.Static("/", *rootDir)

	fmt.Println("Starting Server:", *httpServ)
	e.Run(*httpServ)
}

func checkAuth(user, passwd string) bool {
	return true
}

func requestAddRsvp(c *echo.Context) error {
	name := c.Form("name")
	email := c.Form("email")
	res := c.Form("response")
	if name == "" || email == "" {
		c.String(http.StatusBadRequest, "Name and Email must be given. Please go back and try again.")
		return nil
	}

	rsvp := Rsvp{0, name, email, res, time.Now()}
	if err := addRsvp(rsvp); err != nil {
		c.String(http.StatusInternalServerError,
			"Failed to add RSVP at this time. Please try again later")
	}

	c.HTML(http.StatusOK, saveSuccess)
	return nil
}

func requestListRsvp(c *echo.Context) error {
	w := c.Response()
	w.Header().Add("Content-Type", "text/plain")
	listRsvp(w)
	return nil
}

func requestBoltBackup(c *echo.Context) error {
	w := c.Response()

	err := db.View(func(tx *bolt.Tx) error {
		w.Header().Set("Content-Type", "application/octet-stream")
		w.Header().Set("Content-Disposition", `attachment; filename="rsvp.boltdb"`)
		w.Header().Set("Content-Length", strconv.Itoa(int(tx.Size())))
		_, err := tx.WriteTo(w)
		return err
	})

	if err != nil {
		c.String(http.StatusInternalServerError, err.Error())
	}
	return err
}
<commit_msg>use gopkg for echo v1 until we upgrade<commit_after>package main

import (
	"fmt"
	"net/http"
	"strconv"
	"time"

	"github.com/boltdb/bolt"
	echo "gopkg.in/labstack/echo.v1"
	"gopkg.in/labstack/echo.v1/middleware"
)

var saveSuccess = `
<meta http-equiv="Refresh" content="5; url=/" />

You have Successfully RSVP'd.  Thank you.  You will now be Redirected.

`

func echoServer() {
	e := echo.New()
	e.Use(middleware.Logger())
	e.Post("/rsvp", requestAddRsvp)

	admin := e.Group("/rsvp")
	admin.Use(middleware.BasicAuth(checkAuth))
	admin.Get("/list", requestListRsvp)
	admin.Get("/backup", requestBoltBackup)

	e.Static("/", *rootDir)

	fmt.Println("Starting Server:", *httpServ)
	e.Run(*httpServ)
}

func checkAuth(user, passwd string) bool {
	return true
}

func requestAddRsvp(c *echo.Context) error {
	name := c.Form("name")
	email := c.Form("email")
	res := c.Form("response")
	if name == "" || email == "" {
		c.String(http.StatusBadRequest, "Name and Email must be given. Please go back and try again.")
		return nil
	}

	rsvp := Rsvp{0, name, email, res, time.Now()}
	if err := addRsvp(rsvp); err != nil {
		c.String(http.StatusInternalServerError,
			"Failed to add RSVP at this time. Please try again later")
	}

	c.HTML(http.StatusOK, saveSuccess)
	return nil
}

func requestListRsvp(c *echo.Context) error {
	w := c.Response()
	w.Header().Add("Content-Type", "text/plain")
	listRsvp(w)
	return nil
}

func requestBoltBackup(c *echo.Context) error {
	w := c.Response()

	err := db.View(func(tx *bolt.Tx) error {
		w.Header().Set("Content-Type", "application/octet-stream")
		w.Header().Set("Content-Disposition", `attachment; filename="rsvp.boltdb"`)
		w.Header().Set("Content-Length", strconv.Itoa(int(tx.Size())))
		_, err := tx.WriteTo(w)
		return err
	})

	if err != nil {
		c.String(http.StatusInternalServerError, err.Error())
	}
	return err
}
<|endoftext|>


<commit_before>package multiconfig

import (
	"flag"
	"fmt"
	"os"
	"reflect"
	"strings"

	"github.com/fatih/structs"
)

// FlagLoader satisfies the loader interface. It creates on the fly flags based
// on the field names and parses them to load into the given pointer of struct
// s.
type FlagLoader struct {
	// Prefix prepends the prefix to each flag name i.e:
	// --foo is converted to --prefix-foo.
	// --foo-bar is converted to --prefix-foo-bar.
	Prefix string

	// EnvPrefix is just a placeholder to print the correct usages when an
	// EnvLoader is used
	EnvPrefix string

	// args defines a custom argument list that overides os.Args[]
	args []string
}

// Load loads the source into the config defined by struct s
func (f *FlagLoader) Load(s interface{}) error {
	strct := structs.New(s)
	structName := strct.Name()

	flagSet := flag.NewFlagSet(structName, flag.ExitOnError)

	for _, field := range strct.Fields() {
		f.processField(flagSet, field.Name(), field)
	}

	flagSet.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
		flagSet.PrintDefaults()
		fmt.Fprintf(os.Stderr, "\nGenerated environment variables:\n")
		e := &EnvironmentLoader{f.EnvPrefix}
		e.PrintEnvs(s)
		fmt.Println("")
	}

	args := os.Args[1:]
	if f.args != nil {
		args = f.args
	}

	return flagSet.Parse(args)
}

// processField generates a flag based on the given field and fieldName. If a
// nested struct is detected, a flag for each field of that nested struct is
// generated too.
func (f *FlagLoader) processField(flagSet *flag.FlagSet, fieldName string, field *structs.Field) error {
	switch field.Kind() {
	case reflect.Struct:
		for _, ff := range field.Fields() {
			if err := f.processField(flagSet, field.Name()+"-"+ff.Name(), ff); err != nil {
				return err
			}
		}
	default:
		// Add custom prefix to the flag if it's set
		if f.Prefix != "" {
			fieldName = f.Prefix + "-" + fieldName
		}

		flagSet.Var(newFieldValue(field), flagName(fieldName), flagUsage(fieldName))
	}

	return nil
}

// fieldValue satisfies the flag.Value and flag.Getter interfaces
type fieldValue structs.Field

func newFieldValue(f *structs.Field) *fieldValue {
	fl := fieldValue(*f)
	return &fl
}

func (f *fieldValue) Set(val string) error {
	field := (*structs.Field)(f)
	return fieldSet(field, val)
}

func (f *fieldValue) String() string {
	fl := (*structs.Field)(f)
	return fmt.Sprintf("%v", fl.Value())
}

func (f *fieldValue) Get() interface{} {
	fl := (*structs.Field)(f)
	return fl.Value()
}

// This is an unexported interface, be careful about it.
// https://code.google.com/p/go/source/browse/src/pkg/flag/flag.go?name=release#101
func (f *fieldValue) IsBoolFlag() bool {
	fl := (*structs.Field)(f)
	if fl.Kind() == reflect.Bool {
		return true
	}
	return false
}

func flagUsage(name string) string { return fmt.Sprintf("Change value of %s.", name) }

func flagName(name string) string { return strings.ToLower(name) }
<commit_msg>flag: expose Args for flexibility<commit_after>package multiconfig

import (
	"flag"
	"fmt"
	"os"
	"reflect"
	"strings"

	"github.com/fatih/structs"
)

// FlagLoader satisfies the loader interface. It creates on the fly flags based
// on the field names and parses them to load into the given pointer of struct
// s.
type FlagLoader struct {
	// Prefix prepends the prefix to each flag name i.e:
	// --foo is converted to --prefix-foo.
	// --foo-bar is converted to --prefix-foo-bar.
	Prefix string

	// EnvPrefix is just a placeholder to print the correct usages when an
	// EnvLoader is used
	EnvPrefix string

	// Args defines a custom argument list. If nil, os.Args[1:] is used.
	Args []string
}

// Load loads the source into the config defined by struct s
func (f *FlagLoader) Load(s interface{}) error {
	strct := structs.New(s)
	structName := strct.Name()

	flagSet := flag.NewFlagSet(structName, flag.ExitOnError)

	for _, field := range strct.Fields() {
		f.processField(flagSet, field.Name(), field)
	}

	flagSet.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
		flagSet.PrintDefaults()
		fmt.Fprintf(os.Stderr, "\nGenerated environment variables:\n")
		e := &EnvironmentLoader{f.EnvPrefix}
		e.PrintEnvs(s)
		fmt.Println("")
	}

	args := os.Args[1:]
	if f.Args != nil {
		args = f.Args
	}

	return flagSet.Parse(args)
}

// processField generates a flag based on the given field and fieldName. If a
// nested struct is detected, a flag for each field of that nested struct is
// generated too.
func (f *FlagLoader) processField(flagSet *flag.FlagSet, fieldName string, field *structs.Field) error {
	switch field.Kind() {
	case reflect.Struct:
		for _, ff := range field.Fields() {
			if err := f.processField(flagSet, field.Name()+"-"+ff.Name(), ff); err != nil {
				return err
			}
		}
	default:
		// Add custom prefix to the flag if it's set
		if f.Prefix != "" {
			fieldName = f.Prefix + "-" + fieldName
		}

		flagSet.Var(newFieldValue(field), flagName(fieldName), flagUsage(fieldName))
	}

	return nil
}

// fieldValue satisfies the flag.Value and flag.Getter interfaces
type fieldValue structs.Field

func newFieldValue(f *structs.Field) *fieldValue {
	fl := fieldValue(*f)
	return &fl
}

func (f *fieldValue) Set(val string) error {
	field := (*structs.Field)(f)
	return fieldSet(field, val)
}

func (f *fieldValue) String() string {
	fl := (*structs.Field)(f)
	return fmt.Sprintf("%v", fl.Value())
}

func (f *fieldValue) Get() interface{} {
	fl := (*structs.Field)(f)
	return fl.Value()
}

// This is an unexported interface, be careful about it.
// https://code.google.com/p/go/source/browse/src/pkg/flag/flag.go?name=release#101
func (f *fieldValue) IsBoolFlag() bool {
	fl := (*structs.Field)(f)
	if fl.Kind() == reflect.Bool {
		return true
	}
	return false
}

func flagUsage(name string) string { return fmt.Sprintf("Change value of %s.", name) }

func flagName(name string) string { return strings.ToLower(name) }
<|endoftext|>


<commit_before>package flow

import (
	"os"
	"os/signal"
	"sync"
	"sync/atomic"
	"syscall"
	"time"
)

type Flow struct {
	errChan  chan error
	stopChan chan struct{}
	ref      *int32
	wg       sync.WaitGroup
	Parent   *Flow
	Children []*Flow
	stoped   int32

	mutex sync.Mutex
}

func New(n int) *Flow {
	f := &Flow{
		errChan:  make(chan error, 1),
		stopChan: make(chan struct{}),
		ref:      new(int32),
	}
	f.Add(n)
	return f
}

const (
	F_CLOSED  = true
	F_TIMEOUT = false
)

func (f *Flow) CloseOrWait(duration time.Duration) bool {
	select {
	case <-time.After(duration):
		return F_TIMEOUT
	case <-f.IsClose():
		return F_CLOSED
	}
}

func (f *Flow) Error(err error) {
	f.errChan <- err
}

func (f *Flow) Fork(n int) *Flow {
	f2 := New(n)
	f2.Parent = f
	f.Children = append(f.Children, f2)
	f.Add(1) // for f2
	return f2
}

func (f *Flow) StopAll() {
	flow := f
	for flow.Parent != nil {
		flow = flow.Parent
	}
	flow.Stop()
}

func (f *Flow) Close() {
	f.Stop()
	f.wait()
}

func (f *Flow) Stop() {
	if !atomic.CompareAndSwapInt32(&f.stoped, 0, 1) {
		return
	}

	close(f.stopChan)
	for _, cf := range f.Children {
		cf.Stop()
	}
}

func (f *Flow) IsClosed() bool {
	return atomic.LoadInt32(&f.stoped) == 1
}

func (f *Flow) IsClose() chan struct{} {
	return f.stopChan
}

func (f *Flow) Add(n int) {
	atomic.AddInt32(f.ref, int32(n))
	f.wg.Add(n)
}

func (f *Flow) Done() {
	f.wg.Done()
	if atomic.AddInt32(f.ref, -1) == 0 {
		f.Stop()
	}
}

func (f *Flow) wait() {
	<-f.stopChan
	f.wg.Wait()

	if f.Parent != nil {
		f.Parent.Done()
	}
}

func (f *Flow) Wait() error {
	signalChan := make(chan os.Signal)
	signal.Notify(signalChan,
		os.Interrupt, os.Kill, syscall.SIGTERM, syscall.SIGHUP)
	var err error
	select {
	case <-f.IsClose():
	case <-signalChan:
		f.Stop()
	case err = <-f.errChan:
		if err != nil {
			f.Stop()
		}
	}
	f.wait()
	return err
}
<commit_msg>add debug and fix bugs<commit_after>package flow

import (
	"os"
	"os/signal"
	"sync"
	"sync/atomic"
	"syscall"
	"time"

	"gopkg.in/logex.v1"
)

type Flow struct {
	Debug    *bool
	errChan  chan error
	stopChan chan struct{}
	ref      *int32
	wg       sync.WaitGroup
	Parent   *Flow
	Children []*Flow
	stoped   int32
	onClose  func()

	mutex sync.Mutex
}

func New(n int) *Flow {
	debug := false
	f := &Flow{
		Debug:    &debug,
		errChan:  make(chan error, 1),
		stopChan: make(chan struct{}),
		ref:      new(int32),
	}
	f.Add(n)
	return f
}

func (f *Flow) SetOnClose(exit func()) {
	f.onClose = exit
}

const (
	F_CLOSED  = true
	F_TIMEOUT = false
)

func (f *Flow) CloseOrWait(duration time.Duration) bool {
	select {
	case <-time.After(duration):
		return F_TIMEOUT
	case <-f.IsClose():
		return F_CLOSED
	}
}

func (f *Flow) Error(err error) {
	f.errChan <- err
}

func (f *Flow) Fork(n int) *Flow {
	f2 := New(n)
	f2.Parent = f
	f2.Debug = f.Debug
	f.Children = append(f.Children, f2)
	f.Add(1) // for f2
	return f2
}

func (f *Flow) StopAll() {
	flow := f
	for flow.Parent != nil {
		flow = flow.Parent
	}
	flow.Stop()
}

func (f *Flow) Close() {
	if *f.Debug {
		logex.DownLevel(1).Info("close")
	}
	f.close()
}

func (f *Flow) close() {
	f.Stop()
	f.wait()
}

func (f *Flow) Stop() {
	if !atomic.CompareAndSwapInt32(&f.stoped, 0, 1) {
		return
	}

	close(f.stopChan)
	for _, cf := range f.Children {
		cf.Stop()
	}
	if f.onClose != nil {
		f.onClose()
	}
}

func (f *Flow) IsClosed() bool {
	return atomic.LoadInt32(&f.stoped) == 1
}

func (f *Flow) IsClose() chan struct{} {
	return f.stopChan
}

func (f *Flow) Add(n int) {
	atomic.AddInt32(f.ref, int32(n))
	if *f.Debug {
		logex.DownLevel(1).Info("add:", n, "ref:", *f.ref)
	}
	f.wg.Add(n)
}

func (f *Flow) Done() {
	f.wg.Done()
	if atomic.AddInt32(f.ref, -1) == 0 {
		f.Stop()
	}
}

func (f *Flow) DoneAndClose() {
	if *f.Debug {
		logex.DownLevel(1).Info("done and close, ref:", *f.ref)
	}
	f.Done()
	f.close()
}

func (f *Flow) wait() {
	<-f.stopChan
	f.wg.Wait()

	if f.Parent != nil {
		f.Parent.Done()
		f.Parent = nil
	}
}

func (f *Flow) Wait() error {
	signalChan := make(chan os.Signal)
	signal.Notify(signalChan,
		os.Interrupt, os.Kill, syscall.SIGTERM, syscall.SIGHUP)
	var err error
	select {
	case <-f.IsClose():
	case <-signalChan:
		f.Stop()
	case err = <-f.errChan:
		if err != nil {
			f.Stop()
		}
	}
	f.wait()
	return err
}
<|endoftext|>


<commit_before>// Tideland Go REST Server Library - JSON Web Token - Unit Tests
//
// Copyright (C) 2016 Frank Mueller / Tideland / Oldenburg / Germany
//
// All rights reserved. Use of this source code is governed
// by the new BSD license.

package jwt_test

//--------------------
// IMPORTS
//--------------------

import (
	"encoding/json"
	"testing"
	"time"

	"github.com/tideland/golib/audit"

	"github.com/tideland/gorest/jwt"
)

//--------------------
// TESTS
//--------------------

// TestClaimsMarshalling tests the marshalling of Claims
// to JSON and back.
func TestClaimsMarshalling(t *testing.T) {
	assert := audit.NewTestingAssertion(t, true)
	assert.Logf("testing claims marshalling")
	// First with uninitialised or empty claims.
	var claims jwt.Claims
	jsonValue, err := json.Marshal(claims)
	assert.Equal(string(jsonValue), "{}")
	assert.Nil(err)
	claims = jwt.NewClaims()
	jsonValue, err = json.Marshal(claims)
	assert.Equal(string(jsonValue), "{}")
	assert.Nil(err)
	// Now fill it.
	claims.Set("foo", "yadda")
	claims.Set("bar", 12345)
	assert.Length(claims, 2)
	jsonValue, err = json.Marshal(claims)
	assert.NotNil(jsonValue)
	assert.Nil(err)
	var unmarshalled jwt.Claims
	err = json.Unmarshal(jsonValue, &unmarshalled)
	assert.Nil(err)
	assert.Length(unmarshalled, 2)
	foo, ok := claims.Get("foo")
	assert.Equal(foo, "yadda")
	assert.True(ok)
	bar, ok := claims.GetInt("bar")
	assert.Equal(bar, 12345)
	assert.True(ok)
}

// TestClaimsBasic tests the low level operations
// on claims.
func TestClaimsBasic(t *testing.T) {
	assert := audit.NewTestingAssertion(t, true)
	assert.Logf("testing claims basic functions handling")
	// First with uninitialised claims.
	var claims jwt.Claims
	ok := claims.Contains("foo")
	assert.False(ok)
	nothing, ok := claims.Get("foo")
	assert.Nil(nothing)
	assert.False(ok)
	old := claims.Set("foo", "bar")
	assert.Nil(old)
	old = claims.Delete("foo")
	assert.Nil(old)
	// Now initialise it.
	claims = jwt.NewClaims()
	ok = claims.Contains("foo")
	assert.False(ok)
	nothing, ok = claims.Get("foo")
	assert.Nil(nothing)
	assert.False(ok)
	old = claims.Set("foo", "bar")
	assert.Nil(old)
	ok = claims.Contains("foo")
	assert.True(ok)
	foo, ok := claims.Get("foo")
	assert.Equal(foo, "bar")
	assert.True(ok)
	old = claims.Set("foo", "yadda")
	assert.Equal(old, "bar")
	// Finally delete it.
	old = claims.Delete("foo")
	assert.Equal(old, "yadda")
	old = claims.Delete("foo")
	assert.Nil(old)
	ok = claims.Contains("foo")
	assert.False(ok)
}

// TestClaimsString tests the string operations
// on claims.
func TestClaimsString(t *testing.T) {
	assert := audit.NewTestingAssertion(t, true)
	assert.Logf("testing claims string handling")
	claims := jwt.NewClaims()
	nothing := claims.Set("foo", "bar")
	assert.Nil(nothing)
	var foo string
	foo, ok := claims.GetString("foo")
	assert.Equal(foo, "bar")
	assert.True(ok)
	claims.Set("foo", 4711)
	foo, ok = claims.GetString("foo")
	assert.Equal(foo, "4711")
	assert.True(ok)
}

// TestClaimsInt tests the int operations
// on claims.
func TestClaimsInt(t *testing.T) {
	assert := audit.NewTestingAssertion(t, true)
	assert.Logf("testing claims int handling")
	claims := jwt.NewClaims()
	claims.Set("foo", 4711)
	claims.Set("bar", "4712")
	claims.Set("baz", 4713.0)
	claims.Set("yadda", "nope")
	foo, ok := claims.GetInt("foo")
	assert.Equal(foo, 4711)
	assert.True(ok)
	bar, ok := claims.GetInt("bar")
	assert.Equal(bar, 4712)
	assert.True(ok)
	baz, ok := claims.GetInt("baz")
	assert.Equal(baz, 4713)
	assert.True(ok)
	yadda, ok := claims.GetInt("yadda")
	assert.Equal(yadda, 0)
	assert.False(ok)
}

// TestClaimsFloat64 tests the float64 operations
// on claims.
func TestClaimsFloat64(t *testing.T) {
	assert := audit.NewTestingAssertion(t, true)
	assert.Logf("testing claims float64 handling")
	claims := jwt.NewClaims()
	claims.Set("foo", 4711)
	claims.Set("bar", "4712")
	claims.Set("baz", 4713.0)
	claims.Set("yadda", "nope")
	foo, ok := claims.GetFloat64("foo")
	assert.Equal(foo, 4711.0)
	assert.True(ok)
	bar, ok := claims.GetFloat64("bar")
	assert.Equal(bar, 4712.0)
	assert.True(ok)
	baz, ok := claims.GetFloat64("baz")
	assert.Equal(baz, 4713.0)
	assert.True(ok)
	yadda, ok := claims.GetFloat64("yadda")
	assert.Equal(yadda, 0.0)
	assert.False(ok)
}

// TestClaimsTime tests the time operations
// on claims.
func TestClaimsTime(t *testing.T) {
	assert := audit.NewTestingAssertion(t, true)
	assert.Logf("testing claims time handling")
	goLaunch := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
	claims := jwt.NewClaims()
	claims.SetTime("foo", goLaunch)
	claims.Set("bar", goLaunch.Unix())
	claims.Set("baz", goLaunch.Format(time.RFC3339))
	claims.Set("yadda", "nope")
	foo, ok := claims.GetTime("foo")
	assert.Equal(foo.Unix(), goLaunch.Unix())
	assert.True(ok)
	bar, ok := claims.GetTime("bar")
	assert.Equal(bar.Unix(), goLaunch.Unix())
	assert.True(ok)
	baz, ok := claims.GetTime("baz")
	assert.Equal(baz.Unix(), goLaunch.Unix())
	assert.True(ok)
	yadda, ok := claims.GetTime("yadda")
	assert.Equal(yadda, time.Time{})
	assert.False(ok)
}

// TestClaimsExpiration checks the setting, getting, and
// deleting of the expiration claim.
func TestClaimsExpiration(t *testing.T) {
	assert := audit.NewTestingAssertion(t, true)
	assert.Logf("testing claim \"exp\"")
	goLaunch := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
	claims := jwt.NewClaims()
	exp, ok := claims.Expiration()
	assert.False(ok)
	none := claims.SetExpiration(goLaunch)
	assert.Equal(none, time.Time{})
	exp, ok = claims.Expiration()
	assert.Equal(exp.Unix(), goLaunch.Unix())
	assert.True(ok)
	old := claims.DeleteExpiration()
	assert.Equal(old.Unix(), exp.Unix())
	exp, ok = claims.Expiration()
	assert.False(ok)
}

// TestClaimsIdentifier checks the setting, getting, and
// deleting of the identifier claim.
func TestClaimsIdentifier(t *testing.T) {
	assert := audit.NewTestingAssertion(t, true)
	assert.Logf("testing claim \"jti\"")
	identifier := "foo"
	claims := jwt.NewClaims()
	jti, ok := claims.Identifier()
	assert.False(ok)
	none := claims.SetIdentifier(identifier)
	assert.Equal(none, "")
	jti, ok = claims.Identifier()
	assert.Equal(jti, identifier)
	assert.True(ok)
	old := claims.DeleteIdentifier()
	assert.Equal(old, jti)
	jti, ok = claims.Identifier()
	assert.False(ok)
}

// TestClaimsIssuedAt checks the setting, getting, and
// deleting of the issued at claim.
func TestClaimsIssuedAt(t *testing.T) {
	assert := audit.NewTestingAssertion(t, true)
	assert.Logf("testing claim \"iat\"")
	goLaunch := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
	claims := jwt.NewClaims()
	iat, ok := claims.IssuedAt()
	assert.False(ok)
	none := claims.SetIssuedAt(goLaunch)
	assert.Equal(none, time.Time{})
	iat, ok = claims.IssuedAt()
	assert.Equal(iat.Unix(), goLaunch.Unix())
	assert.True(ok)
	old := claims.DeleteIssuedAt()
	assert.Equal(old.Unix(), iat.Unix())
	iat, ok = claims.IssuedAt()
	assert.False(ok)
}

// TestClaimsIssuer checks the setting, getting, and
// deleting of the issuer claim.
func TestClaimsIssuer(t *testing.T) {
	assert := audit.NewTestingAssertion(t, true)
	assert.Logf("testing claim \"iss\"")
	issuer := "foo"
	claims := jwt.NewClaims()
	iss, ok := claims.Issuer()
	assert.False(ok)
	none := claims.SetIssuer(issuer)
	assert.Equal(none, "")
	iss, ok = claims.Issuer()
	assert.Equal(iss, issuer)
	assert.True(ok)
	old := claims.DeleteIssuer()
	assert.Equal(old, iss)
	iss, ok = claims.Issuer()
	assert.False(ok)
}

// TestClaimsNotBefore checks the setting, getting, and
// deleting of the not before claim.
func TestClaimsNotBefore(t *testing.T) {
	assert := audit.NewTestingAssertion(t, true)
	assert.Logf("testing claim \"nbf\"")
	goLaunch := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
	claims := jwt.NewClaims()
	nbf, ok := claims.NotBefore()
	assert.False(ok)
	none := claims.SetNotBefore(goLaunch)
	assert.Equal(none, time.Time{})
	nbf, ok = claims.NotBefore()
	assert.Equal(nbf.Unix(), goLaunch.Unix())
	assert.True(ok)
	old := claims.DeleteNotBefore()
	assert.Equal(old.Unix(), nbf.Unix())
	nbf, ok = claims.NotBefore()
	assert.False(ok)
}

// TestClaimsValidity checks the validation of the not before
// and the expiring time.
func TestClaimsValidity(t *testing.T) {
	assert := audit.NewTestingAssertion(t, true)
	assert.Logf("testing claims validity")
	// Fresh claims.
	now := time.Now()
	leeway := time.Minute
	claims := jwt.NewClaims()
	valid := claims.IsAlreadyValid(leeway)
	assert.True(valid)
	valid = claims.IsStillValid(leeway)
	assert.True(valid)
	valid = claims.IsValid(leeway)
	assert.True(valid)
	// Set times.
	nbf := now.Add(-time.Hour)
	exp := now.Add(time.Hour)
	claims.SetNotBefore(nbf)
	valid = claims.IsAlreadyValid(leeway)
	assert.True(valid)
	claims.SetExpiration(exp)
	valid = claims.IsStillValid(leeway)
	assert.True(valid)
	valid = claims.IsValid(leeway)
	assert.True(valid)
	// Invalid claims.
	nbf = now.Add(time.Hour)
	exp = now.Add(-time.Hour)
	claims.SetNotBefore(nbf)
	claims.DeleteExpiration()
	valid = claims.IsAlreadyValid(leeway)
	assert.False(valid)
	valid = claims.IsValid(leeway)
	assert.False(valid)
	claims.DeleteNotBefore()
	claims.SetExpiration(exp)
	valid = claims.IsStillValid(leeway)
	assert.False(valid)
	valid = claims.IsValid(leeway)
	assert.False(valid)
	claims.SetNotBefore(nbf)
	valid = claims.IsValid(leeway)
	assert.False(valid)
}

// EOF
<commit_msg>Added tests for audience and subject<commit_after>// Tideland Go REST Server Library - JSON Web Token - Unit Tests
//
// Copyright (C) 2016 Frank Mueller / Tideland / Oldenburg / Germany
//
// All rights reserved. Use of this source code is governed
// by the new BSD license.

package jwt_test

//--------------------
// IMPORTS
//--------------------

import (
	"encoding/json"
	"testing"
	"time"

	"github.com/tideland/golib/audit"

	"github.com/tideland/gorest/jwt"
)

//--------------------
// TESTS
//--------------------

// TestClaimsMarshalling tests the marshalling of Claims
// to JSON and back.
func TestClaimsMarshalling(t *testing.T) {
	assert := audit.NewTestingAssertion(t, true)
	assert.Logf("testing claims marshalling")
	// First with uninitialised or empty claims.
	var claims jwt.Claims
	jsonValue, err := json.Marshal(claims)
	assert.Equal(string(jsonValue), "{}")
	assert.Nil(err)
	claims = jwt.NewClaims()
	jsonValue, err = json.Marshal(claims)
	assert.Equal(string(jsonValue), "{}")
	assert.Nil(err)
	// Now fill it.
	claims.Set("foo", "yadda")
	claims.Set("bar", 12345)
	assert.Length(claims, 2)
	jsonValue, err = json.Marshal(claims)
	assert.NotNil(jsonValue)
	assert.Nil(err)
	var unmarshalled jwt.Claims
	err = json.Unmarshal(jsonValue, &unmarshalled)
	assert.Nil(err)
	assert.Length(unmarshalled, 2)
	foo, ok := claims.Get("foo")
	assert.Equal(foo, "yadda")
	assert.True(ok)
	bar, ok := claims.GetInt("bar")
	assert.Equal(bar, 12345)
	assert.True(ok)
}

// TestClaimsBasic tests the low level operations
// on claims.
func TestClaimsBasic(t *testing.T) {
	assert := audit.NewTestingAssertion(t, true)
	assert.Logf("testing claims basic functions handling")
	// First with uninitialised claims.
	var claims jwt.Claims
	ok := claims.Contains("foo")
	assert.False(ok)
	nothing, ok := claims.Get("foo")
	assert.Nil(nothing)
	assert.False(ok)
	old := claims.Set("foo", "bar")
	assert.Nil(old)
	old = claims.Delete("foo")
	assert.Nil(old)
	// Now initialise it.
	claims = jwt.NewClaims()
	ok = claims.Contains("foo")
	assert.False(ok)
	nothing, ok = claims.Get("foo")
	assert.Nil(nothing)
	assert.False(ok)
	old = claims.Set("foo", "bar")
	assert.Nil(old)
	ok = claims.Contains("foo")
	assert.True(ok)
	foo, ok := claims.Get("foo")
	assert.Equal(foo, "bar")
	assert.True(ok)
	old = claims.Set("foo", "yadda")
	assert.Equal(old, "bar")
	// Finally delete it.
	old = claims.Delete("foo")
	assert.Equal(old, "yadda")
	old = claims.Delete("foo")
	assert.Nil(old)
	ok = claims.Contains("foo")
	assert.False(ok)
}

// TestClaimsString tests the string operations
// on claims.
func TestClaimsString(t *testing.T) {
	assert := audit.NewTestingAssertion(t, true)
	assert.Logf("testing claims string handling")
	claims := jwt.NewClaims()
	nothing := claims.Set("foo", "bar")
	assert.Nil(nothing)
	var foo string
	foo, ok := claims.GetString("foo")
	assert.Equal(foo, "bar")
	assert.True(ok)
	claims.Set("foo", 4711)
	foo, ok = claims.GetString("foo")
	assert.Equal(foo, "4711")
	assert.True(ok)
}

// TestClaimsInt tests the int operations
// on claims.
func TestClaimsInt(t *testing.T) {
	assert := audit.NewTestingAssertion(t, true)
	assert.Logf("testing claims int handling")
	claims := jwt.NewClaims()
	claims.Set("foo", 4711)
	claims.Set("bar", "4712")
	claims.Set("baz", 4713.0)
	claims.Set("yadda", "nope")
	foo, ok := claims.GetInt("foo")
	assert.Equal(foo, 4711)
	assert.True(ok)
	bar, ok := claims.GetInt("bar")
	assert.Equal(bar, 4712)
	assert.True(ok)
	baz, ok := claims.GetInt("baz")
	assert.Equal(baz, 4713)
	assert.True(ok)
	yadda, ok := claims.GetInt("yadda")
	assert.Equal(yadda, 0)
	assert.False(ok)
}

// TestClaimsFloat64 tests the float64 operations
// on claims.
func TestClaimsFloat64(t *testing.T) {
	assert := audit.NewTestingAssertion(t, true)
	assert.Logf("testing claims float64 handling")
	claims := jwt.NewClaims()
	claims.Set("foo", 4711)
	claims.Set("bar", "4712")
	claims.Set("baz", 4713.0)
	claims.Set("yadda", "nope")
	foo, ok := claims.GetFloat64("foo")
	assert.Equal(foo, 4711.0)
	assert.True(ok)
	bar, ok := claims.GetFloat64("bar")
	assert.Equal(bar, 4712.0)
	assert.True(ok)
	baz, ok := claims.GetFloat64("baz")
	assert.Equal(baz, 4713.0)
	assert.True(ok)
	yadda, ok := claims.GetFloat64("yadda")
	assert.Equal(yadda, 0.0)
	assert.False(ok)
}

// TestClaimsTime tests the time operations
// on claims.
func TestClaimsTime(t *testing.T) {
	assert := audit.NewTestingAssertion(t, true)
	assert.Logf("testing claims time handling")
	goLaunch := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
	claims := jwt.NewClaims()
	claims.SetTime("foo", goLaunch)
	claims.Set("bar", goLaunch.Unix())
	claims.Set("baz", goLaunch.Format(time.RFC3339))
	claims.Set("yadda", "nope")
	foo, ok := claims.GetTime("foo")
	assert.Equal(foo.Unix(), goLaunch.Unix())
	assert.True(ok)
	bar, ok := claims.GetTime("bar")
	assert.Equal(bar.Unix(), goLaunch.Unix())
	assert.True(ok)
	baz, ok := claims.GetTime("baz")
	assert.Equal(baz.Unix(), goLaunch.Unix())
	assert.True(ok)
	yadda, ok := claims.GetTime("yadda")
	assert.Equal(yadda, time.Time{})
	assert.False(ok)
}

// TestClaimsAudience checks the setting, getting, and
// deleting of the audience claim.
func TestClaimsAudience(t *testing.T) {
	assert := audit.NewTestingAssertion(t, true)
	assert.Logf("testing claim \"aud\"")
	audience := []string{"foo", "bar", "baz"}
	claims := jwt.NewClaims()
	aud, ok := claims.Audience()
	assert.False(ok)
	none := claims.SetAudience(audience...)
	assert.Equal(none, "")
	aud, ok = claims.Audience()
	assert.Equal(aud, audience)
	assert.True(ok)
	old := claims.DeleteAudience()
	assert.Equal(old, aud)
	aud, ok = claims.Audience()
	assert.False(ok)
}

// TestClaimsExpiration checks the setting, getting, and
// deleting of the expiration claim.
func TestClaimsExpiration(t *testing.T) {
	assert := audit.NewTestingAssertion(t, true)
	assert.Logf("testing claim \"exp\"")
	goLaunch := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
	claims := jwt.NewClaims()
	exp, ok := claims.Expiration()
	assert.False(ok)
	none := claims.SetExpiration(goLaunch)
	assert.Equal(none, time.Time{})
	exp, ok = claims.Expiration()
	assert.Equal(exp.Unix(), goLaunch.Unix())
	assert.True(ok)
	old := claims.DeleteExpiration()
	assert.Equal(old.Unix(), exp.Unix())
	exp, ok = claims.Expiration()
	assert.False(ok)
}

// TestClaimsIdentifier checks the setting, getting, and
// deleting of the identifier claim.
func TestClaimsIdentifier(t *testing.T) {
	assert := audit.NewTestingAssertion(t, true)
	assert.Logf("testing claim \"jti\"")
	identifier := "foo"
	claims := jwt.NewClaims()
	jti, ok := claims.Identifier()
	assert.False(ok)
	none := claims.SetIdentifier(identifier)
	assert.Equal(none, "")
	jti, ok = claims.Identifier()
	assert.Equal(jti, identifier)
	assert.True(ok)
	old := claims.DeleteIdentifier()
	assert.Equal(old, jti)
	jti, ok = claims.Identifier()
	assert.False(ok)
}

// TestClaimsIssuedAt checks the setting, getting, and
// deleting of the issued at claim.
func TestClaimsIssuedAt(t *testing.T) {
	assert := audit.NewTestingAssertion(t, true)
	assert.Logf("testing claim \"iat\"")
	goLaunch := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
	claims := jwt.NewClaims()
	iat, ok := claims.IssuedAt()
	assert.False(ok)
	none := claims.SetIssuedAt(goLaunch)
	assert.Equal(none, time.Time{})
	iat, ok = claims.IssuedAt()
	assert.Equal(iat.Unix(), goLaunch.Unix())
	assert.True(ok)
	old := claims.DeleteIssuedAt()
	assert.Equal(old.Unix(), iat.Unix())
	iat, ok = claims.IssuedAt()
	assert.False(ok)
}

// TestClaimsIssuer checks the setting, getting, and
// deleting of the issuer claim.
func TestClaimsIssuer(t *testing.T) {
	assert := audit.NewTestingAssertion(t, true)
	assert.Logf("testing claim \"iss\"")
	issuer := "foo"
	claims := jwt.NewClaims()
	iss, ok := claims.Issuer()
	assert.False(ok)
	none := claims.SetIssuer(issuer)
	assert.Equal(none, "")
	iss, ok = claims.Issuer()
	assert.Equal(iss, issuer)
	assert.True(ok)
	old := claims.DeleteIssuer()
	assert.Equal(old, iss)
	iss, ok = claims.Issuer()
	assert.False(ok)
}

// TestClaimsNotBefore checks the setting, getting, and
// deleting of the not before claim.
func TestClaimsNotBefore(t *testing.T) {
	assert := audit.NewTestingAssertion(t, true)
	assert.Logf("testing claim \"nbf\"")
	goLaunch := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
	claims := jwt.NewClaims()
	nbf, ok := claims.NotBefore()
	assert.False(ok)
	none := claims.SetNotBefore(goLaunch)
	assert.Equal(none, time.Time{})
	nbf, ok = claims.NotBefore()
	assert.Equal(nbf.Unix(), goLaunch.Unix())
	assert.True(ok)
	old := claims.DeleteNotBefore()
	assert.Equal(old.Unix(), nbf.Unix())
	nbf, ok = claims.NotBefore()
	assert.False(ok)
}

// TestClaimsSubject checks the setting, getting, and
// deleting of the subject claim.
func TestClaimsSubject(t *testing.T) {
	assert := audit.NewTestingAssertion(t, true)
	assert.Logf("testing claim \"sub\"")
	subject := "foo"
	claims := jwt.NewClaims()
	sub, ok := claims.Subject()
	assert.False(ok)
	none := claims.SetSubject(subject)
	assert.Equal(none, "")
	sub, ok = claims.Subject()
	assert.Equal(sub, subject)
	assert.True(ok)
	old := claims.DeleteSubject()
	assert.Equal(old, sub)
	sub, ok = claims.Subject()
	assert.False(ok)
}

// TestClaimsValidity checks the validation of the not before
// and the expiring time.
func TestClaimsValidity(t *testing.T) {
	assert := audit.NewTestingAssertion(t, true)
	assert.Logf("testing claims validity")
	// Fresh claims.
	now := time.Now()
	leeway := time.Minute
	claims := jwt.NewClaims()
	valid := claims.IsAlreadyValid(leeway)
	assert.True(valid)
	valid = claims.IsStillValid(leeway)
	assert.True(valid)
	valid = claims.IsValid(leeway)
	assert.True(valid)
	// Set times.
	nbf := now.Add(-time.Hour)
	exp := now.Add(time.Hour)
	claims.SetNotBefore(nbf)
	valid = claims.IsAlreadyValid(leeway)
	assert.True(valid)
	claims.SetExpiration(exp)
	valid = claims.IsStillValid(leeway)
	assert.True(valid)
	valid = claims.IsValid(leeway)
	assert.True(valid)
	// Invalid claims.
	nbf = now.Add(time.Hour)
	exp = now.Add(-time.Hour)
	claims.SetNotBefore(nbf)
	claims.DeleteExpiration()
	valid = claims.IsAlreadyValid(leeway)
	assert.False(valid)
	valid = claims.IsValid(leeway)
	assert.False(valid)
	claims.DeleteNotBefore()
	claims.SetExpiration(exp)
	valid = claims.IsStillValid(leeway)
	assert.False(valid)
	valid = claims.IsValid(leeway)
	assert.False(valid)
	claims.SetNotBefore(nbf)
	valid = claims.IsValid(leeway)
	assert.False(valid)
}

// EOF
<|endoftext|>


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

package run

import (
	"flag"
	"fmt"
	"io"
	"os"
	"os/exec"
	"path/filepath"

	"github.com/kardianos/govendor/context"
	"github.com/kardianos/govendor/help"
	"github.com/kardianos/govendor/migrate"
)

func (r *runner) Init(w io.Writer, subCmdArgs []string) (help.HelpMessage, error) {
	flags := flag.NewFlagSet("init", flag.ContinueOnError)
	flags.SetOutput(nullWriter{})
	err := flags.Parse(subCmdArgs)
	if err != nil {
		return help.MsgInit, err
	}
	ctx, err := r.NewContextWD(context.RootWD)
	if err != nil {
		return help.MsgNone, err
	}
	ctx.VendorFile.Ignore = "test" // Add default ignore rule.
	err = ctx.WriteVendorFile()
	if err != nil {
		return help.MsgNone, err
	}
	err = os.MkdirAll(filepath.Join(ctx.RootDir, ctx.VendorFolder), 0777)
	return help.MsgNone, err
}
func (r *runner) Migrate(w io.Writer, subCmdArgs []string) (help.HelpMessage, error) {
	flags := flag.NewFlagSet("migrate", flag.ContinueOnError)
	flags.SetOutput(nullWriter{})
	err := flags.Parse(subCmdArgs)
	if err != nil {
		return help.MsgMigrate, err
	}

	from := migrate.From("auto")
	if len(flags.Args()) > 0 {
		from = migrate.From(flags.Arg(0))
	}
	err = migrate.MigrateWD(from)
	if err != nil {
		return help.MsgNone, err
	}
	fmt.Fprintf(w, `You may wish to run "govendor sync" now.%s`, "\n")
	return help.MsgNone, nil
}

func (r *runner) Get(w io.Writer, subCmdArgs []string) (help.HelpMessage, error) {
	flags := flag.NewFlagSet("get", flag.ContinueOnError)
	flags.SetOutput(nullWriter{})

	insecure := flags.Bool("insecure", false, "allows insecure connection")
	verbose := flags.Bool("v", false, "verbose")

	flags.Bool("u", false, "update") // For compatibility with "go get".

	err := flags.Parse(subCmdArgs)
	if err != nil {
		return help.MsgGet, err
	}
	logger := w
	if !*verbose {
		logger = nil
	}
	for _, a := range flags.Args() {
		pkg, err := context.Get(logger, a, *insecure)
		if err != nil {
			return help.MsgNone, err
		}

		r.GoCmd("install", []string{pkg.Path})
	}
	return help.MsgNone, nil
}

func (r *runner) GoCmd(subcmd string, args []string) (help.HelpMessage, error) {
	ctx, err := r.NewContextWD(context.RootVendorOrWDOrFirstGOPATH)
	if err != nil {
		return help.MsgNone, err
	}
	list, err := ctx.Status()
	if err != nil {
		return help.MsgNone, err
	}
	cgp, err := currentGoPath(ctx)
	if err != nil {
		return help.MsgNone, err
	}

	otherArgs := make([]string, 1, len(args)+1)
	otherArgs[0] = subcmd

	// Expand any status flags in-place. Some wrapped commands the order is
	// important to the operation of the command.
	for _, a := range args {
		if a[0] == '+' {
			f, err := parseFilter(cgp, []string{a})
			if err != nil {
				return help.MsgNone, err
			}
			for _, item := range list {
				if f.HasStatus(item) {
					add := item.Local
					// "go tool vet" takes dirs, not pkgs, so special case it.
					if subcmd == "tool" && len(args) > 0 && args[0] == "vet" {
						add = filepath.Join(ctx.RootGopath, add)
					}
					otherArgs = append(otherArgs, add)
				}
			}
		} else {
			otherArgs = append(otherArgs, a)
		}
	}

	cmd := exec.Command("go", otherArgs...)
	cmd.Stderr = os.Stderr
	cmd.Stdout = os.Stdout
	return help.MsgNone, cmd.Run()
}

func (r *runner) Status(w io.Writer, subCmdArgs []string) (help.HelpMessage, error) {
	flags := flag.NewFlagSet("status", flag.ContinueOnError)
	flags.SetOutput(nullWriter{})
	err := flags.Parse(subCmdArgs)
	if err != nil {
		return help.MsgStatus, err
	}
	ctx, err := r.NewContextWD(context.RootVendor)
	if err != nil {
		return help.MsgStatus, err
	}
	outOfDate, err := ctx.VerifyVendor()
	if err != nil {
		return help.MsgStatus, err
	}
	if len(outOfDate) == 0 {
		return help.MsgNone, nil
	}
	fmt.Fprintf(w, "The following packages are missing or modified locally:\n")
	for _, pkg := range outOfDate {
		fmt.Fprintf(w, "\t%s\n", pkg.Path)
	}
	return help.MsgNone, fmt.Errorf("status failed for %d package(s)", len(outOfDate))
}
<commit_msg>Do not run non-matching filtered commands.<commit_after>// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package run

import (
	"flag"
	"fmt"
	"io"
	"os"
	"os/exec"
	"path/filepath"

	"github.com/kardianos/govendor/context"
	"github.com/kardianos/govendor/help"
	"github.com/kardianos/govendor/migrate"
)

func (r *runner) Init(w io.Writer, subCmdArgs []string) (help.HelpMessage, error) {
	flags := flag.NewFlagSet("init", flag.ContinueOnError)
	flags.SetOutput(nullWriter{})
	err := flags.Parse(subCmdArgs)
	if err != nil {
		return help.MsgInit, err
	}
	ctx, err := r.NewContextWD(context.RootWD)
	if err != nil {
		return help.MsgNone, err
	}
	ctx.VendorFile.Ignore = "test" // Add default ignore rule.
	err = ctx.WriteVendorFile()
	if err != nil {
		return help.MsgNone, err
	}
	err = os.MkdirAll(filepath.Join(ctx.RootDir, ctx.VendorFolder), 0777)
	return help.MsgNone, err
}
func (r *runner) Migrate(w io.Writer, subCmdArgs []string) (help.HelpMessage, error) {
	flags := flag.NewFlagSet("migrate", flag.ContinueOnError)
	flags.SetOutput(nullWriter{})
	err := flags.Parse(subCmdArgs)
	if err != nil {
		return help.MsgMigrate, err
	}

	from := migrate.From("auto")
	if len(flags.Args()) > 0 {
		from = migrate.From(flags.Arg(0))
	}
	err = migrate.MigrateWD(from)
	if err != nil {
		return help.MsgNone, err
	}
	fmt.Fprintf(w, `You may wish to run "govendor sync" now.%s`, "\n")
	return help.MsgNone, nil
}

func (r *runner) Get(w io.Writer, subCmdArgs []string) (help.HelpMessage, error) {
	flags := flag.NewFlagSet("get", flag.ContinueOnError)
	flags.SetOutput(nullWriter{})

	insecure := flags.Bool("insecure", false, "allows insecure connection")
	verbose := flags.Bool("v", false, "verbose")

	flags.Bool("u", false, "update") // For compatibility with "go get".

	err := flags.Parse(subCmdArgs)
	if err != nil {
		return help.MsgGet, err
	}
	logger := w
	if !*verbose {
		logger = nil
	}
	for _, a := range flags.Args() {
		pkg, err := context.Get(logger, a, *insecure)
		if err != nil {
			return help.MsgNone, err
		}

		r.GoCmd("install", []string{pkg.Path})
	}
	return help.MsgNone, nil
}

func (r *runner) GoCmd(subcmd string, args []string) (help.HelpMessage, error) {
	ctx, err := r.NewContextWD(context.RootVendorOrWDOrFirstGOPATH)
	if err != nil {
		return help.MsgNone, err
	}
	list, err := ctx.Status()
	if err != nil {
		return help.MsgNone, err
	}
	cgp, err := currentGoPath(ctx)
	if err != nil {
		return help.MsgNone, err
	}

	otherArgs := make([]string, 1, len(args)+1)
	otherArgs[0] = subcmd

	// We keep track of whether any filtering was requested, and if so,
	// whether a filter actually matched any items.
	var filtersRequested, filtersFound bool

	// Expand any status flags in-place. Some wrapped commands the order is
	// important to the operation of the command.
	for _, a := range args {
		if len(a) > 0 && a[0] == '+' {
			filtersRequested = true

			f, err := parseFilter(cgp, []string{a})
			if err != nil {
				return help.MsgNone, err
			}

			for _, item := range list {
				if f.HasStatus(item) {
					filtersFound = true

					add := item.Local
					// "go tool vet" takes dirs, not pkgs, so special case it.
					if subcmd == "tool" && len(args) > 0 && args[0] == "vet" {
						add = filepath.Join(ctx.RootGopath, add)
					}
					otherArgs = append(otherArgs, add)
				}
			}
		} else {
			otherArgs = append(otherArgs, a)
		}
	}

	// If at least one filter was requested but we didn't match any packages,
	// we want to bail out; otherwise, the command will behave as if we ran it
	// against the current package instead of the requested filters' packages.
	if filtersRequested && !filtersFound {
		return help.MsgNone, nil
	}

	cmd := exec.Command("go", otherArgs...)
	cmd.Stderr = os.Stderr
	cmd.Stdout = os.Stdout
	return help.MsgNone, cmd.Run()
}

func (r *runner) Status(w io.Writer, subCmdArgs []string) (help.HelpMessage, error) {
	flags := flag.NewFlagSet("status", flag.ContinueOnError)
	flags.SetOutput(nullWriter{})
	err := flags.Parse(subCmdArgs)
	if err != nil {
		return help.MsgStatus, err
	}
	ctx, err := r.NewContextWD(context.RootVendor)
	if err != nil {
		return help.MsgStatus, err
	}
	outOfDate, err := ctx.VerifyVendor()
	if err != nil {
		return help.MsgStatus, err
	}
	if len(outOfDate) == 0 {
		return help.MsgNone, nil
	}
	fmt.Fprintf(w, "The following packages are missing or modified locally:\n")
	for _, pkg := range outOfDate {
		fmt.Fprintf(w, "\t%s\n", pkg.Path)
	}
	return help.MsgNone, fmt.Errorf("status failed for %d package(s)", len(outOfDate))
}
<|endoftext|>


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

package fuseops

import (
	"bytes"
	"log"
	"time"
	"unsafe"

	"github.com/jacobsa/fuse/internal/fusekernel"
	"github.com/jacobsa/fuse/internal/fuseshim"
	"golang.org/x/net/context"
)

// This function is an implementation detail of the fuse package, and must not
// be called by anyone else.
//
// Convert the supplied fuse kernel message to an Op. sendReply will be used to
// send the reply back to the kernel once the user calls o.Respond. That
// function is responsible for destroying the message.
//
// It is guaranteed that o != nil. If the op is unknown, a special unexported
// type will be used.
//
// The debug logging function and error logger may be nil.
func Convert(
	opCtx context.Context,
	m *fuseshim.Message,
	protocol fusekernel.Protocol,
	debugLogForOp func(int, string, ...interface{}),
	errorLogger *log.Logger,
	sendReply replyFunc) (o Op) {
	var co *commonOp

	var io internalOp
	switch m.Hdr.Opcode {
	case fusekernel.OpLookup:
		buf := m.Bytes()
		n := len(buf)
		if n == 0 || buf[n-1] != '\x00' {
			goto corrupt
		}

		to := &LookUpInodeOp{
			Parent: InodeID(m.Hdr.Nodeid),
			Name:   string(buf[:n-1]),
		}
		io = to
		co = &to.commonOp

	case fusekernel.OpGetattr:
		to := &GetInodeAttributesOp{
			Inode: InodeID(m.Hdr.Nodeid),
		}
		io = to
		co = &to.commonOp

	case fusekernel.OpSetattr:
		in := (*fusekernel.SetattrIn)(m.Data())
		if m.Len() < unsafe.Sizeof(*in) {
			goto corrupt
		}

		to := &SetInodeAttributesOp{
			Inode: InodeID(m.Hdr.Nodeid),
		}

		valid := fusekernel.SetattrValid(in.Valid)
		if valid&fusekernel.SetattrSize != 0 {
			to.Size = &in.Size
		}

		if valid&fusekernel.SetattrMode != 0 {
			mode := fuseshim.FileMode(in.Mode)
			to.Mode = &mode
		}

		if valid&fusekernel.SetattrAtime != 0 {
			t := time.Unix(int64(in.Atime), int64(in.AtimeNsec))
			to.Atime = &t
		}

		if valid&fusekernel.SetattrMtime != 0 {
			t := time.Unix(int64(in.Mtime), int64(in.MtimeNsec))
			to.Mtime = &t
		}

		io = to
		co = &to.commonOp

	case fusekernel.OpForget:
		in := (*fusekernel.ForgetIn)(m.Data())
		if m.Len() < unsafe.Sizeof(*in) {
			goto corrupt
		}

		to := &ForgetInodeOp{
			Inode: InodeID(m.Hdr.Nodeid),
			N:     in.Nlookup,
		}
		io = to
		co = &to.commonOp

	case fusekernel.OpMkdir:
		size := fusekernel.MkdirInSize(protocol)
		if m.Len() < size {
			goto corrupt
		}
		in := (*fusekernel.MkdirIn)(m.Data())
		name := m.Bytes()[size:]
		i := bytes.IndexByte(name, '\x00')
		if i < 0 {
			goto corrupt
		}
		name = name[:i]

		to := &MkDirOp{
			Parent: InodeID(m.Hdr.Nodeid),
			Name:   string(name),
			Mode:   fuseshim.FileMode(in.Mode),
		}
		io = to
		co = &to.commonOp

	case fusekernel.OpCreate:
		size := fusekernel.CreateInSize(protocol)
		if m.Len() < size {
			goto corrupt
		}
		in := (*fusekernel.CreateIn)(m.Data())
		name := m.Bytes()[size:]
		i := bytes.IndexByte(name, '\x00')
		if i < 0 {
			goto corrupt
		}
		name = name[:i]

		to := &CreateFileOp{
			Parent: InodeID(m.Hdr.Nodeid),
			Name:   string(name),
			Mode:   fuseshim.FileMode(in.Mode),
		}
		io = to
		co = &to.commonOp

	case fusekernel.OpSymlink:
		// m.Bytes() is "newName\0target\0"
		names := m.Bytes()
		if len(names) == 0 || names[len(names)-1] != 0 {
			goto corrupt
		}
		i := bytes.IndexByte(names, '\x00')
		if i < 0 {
			goto corrupt
		}
		newName, target := names[0:i], names[i+1:len(names)-1]

		to := &CreateSymlinkOp{
			Parent: InodeID(m.Hdr.Nodeid),
			Name:   string(newName),
			Target: string(target),
		}
		io = to
		co = &to.commonOp

	case fusekernel.OpRename:
		in := (*fusekernel.RenameIn)(m.Data())
		if m.Len() < unsafe.Sizeof(*in) {
			goto corrupt
		}
		names := m.Bytes()[unsafe.Sizeof(*in):]
		// names should be "old\x00new\x00"
		if len(names) < 4 {
			goto corrupt
		}
		if names[len(names)-1] != '\x00' {
			goto corrupt
		}
		i := bytes.IndexByte(names, '\x00')
		if i < 0 {
			goto corrupt
		}
		oldName, newName := names[:i], names[i+1:len(names)-1]

		to := &RenameOp{
			OldParent: InodeID(m.Hdr.Nodeid),
			OldName:   string(oldName),
			NewParent: InodeID(in.Newdir),
			NewName:   string(newName),
		}
		io = to
		co = &to.commonOp

	case fusekernel.OpUnlink:
		buf := m.Bytes()
		n := len(buf)
		if n == 0 || buf[n-1] != '\x00' {
			goto corrupt
		}

		to := &UnlinkOp{
			Parent: InodeID(m.Hdr.Nodeid),
			Name:   string(buf[:n-1]),
		}
		io = to
		co = &to.commonOp

	case fusekernel.OpRmdir:
		buf := m.Bytes()
		n := len(buf)
		if n == 0 || buf[n-1] != '\x00' {
			goto corrupt
		}

		to := &RmDirOp{
			Parent: InodeID(m.Hdr.Nodeid),
			Name:   string(buf[:n-1]),
		}
		io = to
		co = &to.commonOp

	case fusekernel.OpOpen:
		to := &OpenFileOp{
			Inode: InodeID(m.Hdr.Nodeid),
		}
		io = to
		co = &to.commonOp

	case fusekernel.OpOpendir:
		to := &OpenDirOp{
			Inode: InodeID(m.Hdr.Nodeid),
		}
		io = to
		co = &to.commonOp

	case fusekernel.OpRead:
		in := (*fusekernel.ReadIn)(m.Data())
		if m.Len() < fusekernel.ReadInSize(protocol) {
			goto corrupt
		}

		to := &ReadFileOp{
			Inode:  InodeID(m.Hdr.Nodeid),
			Handle: HandleID(in.Fh),
			Offset: int64(in.Offset),
			Size:   int(in.Size),
		}
		io = to
		co = &to.commonOp

	case fusekernel.OpReaddir:
		in := (*fusekernel.ReadIn)(m.Data())
		if m.Len() < fusekernel.ReadInSize(protocol) {
			goto corrupt
		}

		to := &ReadDirOp{
			Inode:  InodeID(m.Hdr.Nodeid),
			Handle: HandleID(in.Fh),
			Offset: DirOffset(in.Offset),
			Size:   int(in.Size),
		}
		io = to
		co = &to.commonOp

	case fusekernel.OpRelease:
		in := (*fusekernel.ReleaseIn)(m.Data())
		if m.Len() < unsafe.Sizeof(*in) {
			goto corrupt
		}

		to := &ReleaseFileHandleOp{
			Handle: HandleID(in.Fh),
		}
		io = to
		co = &to.commonOp

	case fusekernel.OpReleasedir:
		in := (*fusekernel.ReleaseIn)(m.Data())
		if m.Len() < unsafe.Sizeof(*in) {
			goto corrupt
		}

		to := &ReleaseDirHandleOp{
			Handle: HandleID(in.Fh),
		}
		io = to
		co = &to.commonOp

	case fusekernel.OpWrite:
		in := (*fusekernel.WriteIn)(m.Data())
		size := fusekernel.WriteInSize(protocol)
		if m.Len() < size {
			goto corrupt
		}

		buf := m.Bytes()[size:]
		if len(buf) < int(in.Size) {
			goto corrupt
		}

		to := &WriteFileOp{
			Inode:  InodeID(m.Hdr.Nodeid),
			Handle: HandleID(in.Fh),
			Data:   buf,
			Offset: int64(in.Offset),
		}
		io = to
		co = &to.commonOp

	case fusekernel.OpFsync:
		in := (*fusekernel.FsyncIn)(m.Data())
		if m.Len() < unsafe.Sizeof(*in) {
			goto corrupt
		}

		to := &SyncFileOp{
			Inode:  InodeID(m.Hdr.Nodeid),
			Handle: HandleID(in.Fh),
		}
		io = to
		co = &to.commonOp

	case fusekernel.OpFlush:
		in := (*fusekernel.FlushIn)(m.Data())
		if m.Len() < unsafe.Sizeof(*in) {
			goto corrupt
		}

		to := &FlushFileOp{
			Inode:  InodeID(m.Hdr.Nodeid),
			Handle: HandleID(in.Fh),
		}
		io = to
		co = &to.commonOp

	case fusekernel.OpReadlink:
		to := &ReadSymlinkOp{
			Inode: InodeID(m.Hdr.Nodeid),
		}
		io = to
		co = &to.commonOp

	default:
		to := &unknownOp{
			opCode: m.Hdr.Opcode,
			inode:  InodeID(m.Hdr.Nodeid),
		}
		io = to
		co = &to.commonOp
	}

	co.init(
		opCtx,
		io,
		m.Hdr.Unique,
		sendReply,
		debugLogForOp,
		errorLogger)

	o = io
	return
}

func convertAttributes(
	inode InodeID,
	attr InodeAttributes,
	expiration time.Time) fuseshim.Attr {
	return fuseshim.Attr{
		Inode:  uint64(inode),
		Size:   attr.Size,
		Mode:   attr.Mode,
		Nlink:  uint32(attr.Nlink),
		Atime:  attr.Atime,
		Mtime:  attr.Mtime,
		Ctime:  attr.Ctime,
		Crtime: attr.Crtime,
		Uid:    attr.Uid,
		Gid:    attr.Gid,
		Valid:  convertExpirationTime(expiration),
	}
}

// Convert an absolute cache expiration time to a relative time from now for
// consumption by fuse.
func convertExpirationTime(t time.Time) (d time.Duration) {
	// Fuse represents durations as unsigned 64-bit counts of seconds and 32-bit
	// counts of nanoseconds (cf. http://goo.gl/EJupJV). The bazil.org/fuse
	// package converts time.Duration values to this form in a straightforward
	// way (cf. http://goo.gl/FJhV8j).
	//
	// So negative durations are right out. There is no need to cap the positive
	// magnitude, because 2^64 seconds is well longer than the 2^63 ns range of
	// time.Duration.
	d = t.Sub(time.Now())
	if d < 0 {
		d = 0
	}

	return
}

func convertChildInodeEntry(
	in *ChildInodeEntry,
	out *fuseshim.LookupResponse) {
	out.Node = fuseshim.NodeID(in.Child)
	out.Generation = uint64(in.Generation)
	out.Attr = convertAttributes(in.Child, in.Attributes, in.AttributesExpiration)
	out.EntryValid = convertExpirationTime(in.EntryExpiration)
}
<commit_msg>Fixed some build errors.<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package fuseops

import (
	"bytes"
	"errors"
	"log"
	"time"
	"unsafe"

	"github.com/jacobsa/fuse/internal/fusekernel"
	"github.com/jacobsa/fuse/internal/fuseshim"
	"golang.org/x/net/context"
)

// This function is an implementation detail of the fuse package, and must not
// be called by anyone else.
//
// Convert the supplied fuse kernel message to an Op. sendReply will be used to
// send the reply back to the kernel once the user calls o.Respond. If the op
// is unknown, a special unexported type will be used.
//
// The debug logging function and error logger may be nil. The caller is
// responsible for arranging for the message to be destroyed.
func Convert(
	opCtx context.Context,
	m *fuseshim.Message,
	protocol fusekernel.Protocol,
	debugLogForOp func(int, string, ...interface{}),
	errorLogger *log.Logger,
	sendReply replyFunc) (o Op, err error) {
	var co *commonOp

	var io internalOp
	switch m.Hdr.Opcode {
	case fusekernel.OpLookup:
		buf := m.Bytes()
		n := len(buf)
		if n == 0 || buf[n-1] != '\x00' {
			err = errors.New("Corrupted OpLookup")
			return
		}

		to := &LookUpInodeOp{
			Parent: InodeID(m.Hdr.Nodeid),
			Name:   string(buf[:n-1]),
		}
		io = to
		co = &to.commonOp

	case fusekernel.OpGetattr:
		to := &GetInodeAttributesOp{
			Inode: InodeID(m.Hdr.Nodeid),
		}
		io = to
		co = &to.commonOp

	case fusekernel.OpSetattr:
		in := (*fusekernel.SetattrIn)(m.Data())
		if m.Len() < unsafe.Sizeof(*in) {
			err = errors.New("Corrupted OpSetattr")
			return
		}

		to := &SetInodeAttributesOp{
			Inode: InodeID(m.Hdr.Nodeid),
		}

		valid := fusekernel.SetattrValid(in.Valid)
		if valid&fusekernel.SetattrSize != 0 {
			to.Size = &in.Size
		}

		if valid&fusekernel.SetattrMode != 0 {
			mode := fuseshim.FileMode(in.Mode)
			to.Mode = &mode
		}

		if valid&fusekernel.SetattrAtime != 0 {
			t := time.Unix(int64(in.Atime), int64(in.AtimeNsec))
			to.Atime = &t
		}

		if valid&fusekernel.SetattrMtime != 0 {
			t := time.Unix(int64(in.Mtime), int64(in.MtimeNsec))
			to.Mtime = &t
		}

		io = to
		co = &to.commonOp

	case fusekernel.OpForget:
		in := (*fusekernel.ForgetIn)(m.Data())
		if m.Len() < unsafe.Sizeof(*in) {
			err = errors.New("Corrupted OpForget")
			return
		}

		to := &ForgetInodeOp{
			Inode: InodeID(m.Hdr.Nodeid),
			N:     in.Nlookup,
		}
		io = to
		co = &to.commonOp

	case fusekernel.OpMkdir:
		size := fusekernel.MkdirInSize(protocol)
		if m.Len() < size {
			err = errors.New("Corrupted OpMkdir")
			return
		}
		in := (*fusekernel.MkdirIn)(m.Data())
		name := m.Bytes()[size:]
		i := bytes.IndexByte(name, '\x00')
		if i < 0 {
			err = errors.New("Corrupted OpMkdir")
			return
		}
		name = name[:i]

		to := &MkDirOp{
			Parent: InodeID(m.Hdr.Nodeid),
			Name:   string(name),
			Mode:   fuseshim.FileMode(in.Mode),
		}
		io = to
		co = &to.commonOp

	case fusekernel.OpCreate:
		size := fusekernel.CreateInSize(protocol)
		if m.Len() < size {
			err = errors.New("Corrupted OpCreate")
			return
		}
		in := (*fusekernel.CreateIn)(m.Data())
		name := m.Bytes()[size:]
		i := bytes.IndexByte(name, '\x00')
		if i < 0 {
			err = errors.New("Corrupted OpCreate")
			return
		}
		name = name[:i]

		to := &CreateFileOp{
			Parent: InodeID(m.Hdr.Nodeid),
			Name:   string(name),
			Mode:   fuseshim.FileMode(in.Mode),
		}
		io = to
		co = &to.commonOp

	case fusekernel.OpSymlink:
		// m.Bytes() is "newName\0target\0"
		names := m.Bytes()
		if len(names) == 0 || names[len(names)-1] != 0 {
			err = errors.New("Corrupted OpSymlink")
			return
		}
		i := bytes.IndexByte(names, '\x00')
		if i < 0 {
			err = errors.New("Corrupted OpSymlink")
			return
		}
		newName, target := names[0:i], names[i+1:len(names)-1]

		to := &CreateSymlinkOp{
			Parent: InodeID(m.Hdr.Nodeid),
			Name:   string(newName),
			Target: string(target),
		}
		io = to
		co = &to.commonOp

	case fusekernel.OpRename:
		in := (*fusekernel.RenameIn)(m.Data())
		if m.Len() < unsafe.Sizeof(*in) {
			err = errors.New("Corrupted OpRename")
			return
		}
		names := m.Bytes()[unsafe.Sizeof(*in):]
		// names should be "old\x00new\x00"
		if len(names) < 4 {
			err = errors.New("Corrupted OpRename")
			return
		}
		if names[len(names)-1] != '\x00' {
			err = errors.New("Corrupted OpRename")
			return
		}
		i := bytes.IndexByte(names, '\x00')
		if i < 0 {
			err = errors.New("Corrupted OpRename")
			return
		}
		oldName, newName := names[:i], names[i+1:len(names)-1]

		to := &RenameOp{
			OldParent: InodeID(m.Hdr.Nodeid),
			OldName:   string(oldName),
			NewParent: InodeID(in.Newdir),
			NewName:   string(newName),
		}
		io = to
		co = &to.commonOp

	case fusekernel.OpUnlink:
		buf := m.Bytes()
		n := len(buf)
		if n == 0 || buf[n-1] != '\x00' {
			err = errors.New("Corrupted OpUnlink")
			return
		}

		to := &UnlinkOp{
			Parent: InodeID(m.Hdr.Nodeid),
			Name:   string(buf[:n-1]),
		}
		io = to
		co = &to.commonOp

	case fusekernel.OpRmdir:
		buf := m.Bytes()
		n := len(buf)
		if n == 0 || buf[n-1] != '\x00' {
			err = errors.New("Corrupted OpRmdir")
			return
		}

		to := &RmDirOp{
			Parent: InodeID(m.Hdr.Nodeid),
			Name:   string(buf[:n-1]),
		}
		io = to
		co = &to.commonOp

	case fusekernel.OpOpen:
		to := &OpenFileOp{
			Inode: InodeID(m.Hdr.Nodeid),
		}
		io = to
		co = &to.commonOp

	case fusekernel.OpOpendir:
		to := &OpenDirOp{
			Inode: InodeID(m.Hdr.Nodeid),
		}
		io = to
		co = &to.commonOp

	case fusekernel.OpRead:
		in := (*fusekernel.ReadIn)(m.Data())
		if m.Len() < fusekernel.ReadInSize(protocol) {
			err = errors.New("Corrupted OpRead")
			return
		}

		to := &ReadFileOp{
			Inode:  InodeID(m.Hdr.Nodeid),
			Handle: HandleID(in.Fh),
			Offset: int64(in.Offset),
			Size:   int(in.Size),
		}
		io = to
		co = &to.commonOp

	case fusekernel.OpReaddir:
		in := (*fusekernel.ReadIn)(m.Data())
		if m.Len() < fusekernel.ReadInSize(protocol) {
			err = errors.New("Corrupted OpReaddir")
			return
		}

		to := &ReadDirOp{
			Inode:  InodeID(m.Hdr.Nodeid),
			Handle: HandleID(in.Fh),
			Offset: DirOffset(in.Offset),
			Size:   int(in.Size),
		}
		io = to
		co = &to.commonOp

	case fusekernel.OpRelease:
		in := (*fusekernel.ReleaseIn)(m.Data())
		if m.Len() < unsafe.Sizeof(*in) {
			err = errors.New("Corrupted OpRelease")
			return
		}

		to := &ReleaseFileHandleOp{
			Handle: HandleID(in.Fh),
		}
		io = to
		co = &to.commonOp

	case fusekernel.OpReleasedir:
		in := (*fusekernel.ReleaseIn)(m.Data())
		if m.Len() < unsafe.Sizeof(*in) {
			err = errors.New("Corrupted OpReleasedir")
			return
		}

		to := &ReleaseDirHandleOp{
			Handle: HandleID(in.Fh),
		}
		io = to
		co = &to.commonOp

	case fusekernel.OpWrite:
		in := (*fusekernel.WriteIn)(m.Data())
		size := fusekernel.WriteInSize(protocol)
		if m.Len() < size {
			err = errors.New("Corrupted OpWrite")
			return
		}

		buf := m.Bytes()[size:]
		if len(buf) < int(in.Size) {
			err = errors.New("Corrupted OpWrite")
			return
		}

		to := &WriteFileOp{
			Inode:  InodeID(m.Hdr.Nodeid),
			Handle: HandleID(in.Fh),
			Data:   buf,
			Offset: int64(in.Offset),
		}
		io = to
		co = &to.commonOp

	case fusekernel.OpFsync:
		in := (*fusekernel.FsyncIn)(m.Data())
		if m.Len() < unsafe.Sizeof(*in) {
			err = errors.New("Corrupted OpFsync")
			return
		}

		to := &SyncFileOp{
			Inode:  InodeID(m.Hdr.Nodeid),
			Handle: HandleID(in.Fh),
		}
		io = to
		co = &to.commonOp

	case fusekernel.OpFlush:
		in := (*fusekernel.FlushIn)(m.Data())
		if m.Len() < unsafe.Sizeof(*in) {
			err = errors.New("Corrupted OpFlush")
			return
		}

		to := &FlushFileOp{
			Inode:  InodeID(m.Hdr.Nodeid),
			Handle: HandleID(in.Fh),
		}
		io = to
		co = &to.commonOp

	case fusekernel.OpReadlink:
		to := &ReadSymlinkOp{
			Inode: InodeID(m.Hdr.Nodeid),
		}
		io = to
		co = &to.commonOp

	default:
		to := &unknownOp{
			opCode: m.Hdr.Opcode,
			inode:  InodeID(m.Hdr.Nodeid),
		}
		io = to
		co = &to.commonOp
	}

	co.init(
		opCtx,
		io,
		m.Hdr.Unique,
		sendReply,
		debugLogForOp,
		errorLogger)

	o = io
	return
}

func convertAttributes(
	inode InodeID,
	attr InodeAttributes,
	expiration time.Time) fuseshim.Attr {
	return fuseshim.Attr{
		Inode:  uint64(inode),
		Size:   attr.Size,
		Mode:   attr.Mode,
		Nlink:  uint32(attr.Nlink),
		Atime:  attr.Atime,
		Mtime:  attr.Mtime,
		Ctime:  attr.Ctime,
		Crtime: attr.Crtime,
		Uid:    attr.Uid,
		Gid:    attr.Gid,
		Valid:  convertExpirationTime(expiration),
	}
}

// Convert an absolute cache expiration time to a relative time from now for
// consumption by fuse.
func convertExpirationTime(t time.Time) (d time.Duration) {
	// Fuse represents durations as unsigned 64-bit counts of seconds and 32-bit
	// counts of nanoseconds (cf. http://goo.gl/EJupJV). The bazil.org/fuse
	// package converts time.Duration values to this form in a straightforward
	// way (cf. http://goo.gl/FJhV8j).
	//
	// So negative durations are right out. There is no need to cap the positive
	// magnitude, because 2^64 seconds is well longer than the 2^63 ns range of
	// time.Duration.
	d = t.Sub(time.Now())
	if d < 0 {
		d = 0
	}

	return
}

func convertChildInodeEntry(
	in *ChildInodeEntry,
	out *fuseshim.LookupResponse) {
	out.Node = fuseshim.NodeID(in.Child)
	out.Generation = uint64(in.Generation)
	out.Attr = convertAttributes(in.Child, in.Attributes, in.AttributesExpiration)
	out.EntryValid = convertExpirationTime(in.EntryExpiration)
}
<|endoftext|>


<commit_before>package gkvlite

import (
	"sync"
	"sync/atomic"
	"unsafe"
)

var reclaimable_node = &node{} // Sentinel.

var freeNodeLock sync.Mutex
var freeNodes *node

var freeNodeLocLock sync.Mutex
var freeNodeLocs *nodeLoc

var freeRootNodeLocLock sync.Mutex
var freeRootNodeLocs *rootNodeLoc

var freeStats FreeStats

type FreeStats struct {
	MkNodes    int64
	FreeNodes  int64
	AllocNodes int64

	MkNodeLocs    int64
	FreeNodeLocs  int64
	AllocNodeLocs int64

	MkRootNodeLocs    int64
	FreeRootNodeLocs  int64
	AllocRootNodeLocs int64
}

func (t *Collection) markReclaimable(n *node) {
	t.rootLock.Lock()
	defer t.rootLock.Unlock()
	if n == nil || n.next != nil || n == reclaimable_node {
		return
	}
	n.next = reclaimable_node // Use next pointer as sentinel.
}

func (t *Collection) reclaimNodes_unlocked(n *node, reclaimLater *[2]*node) int64 {
	if n == nil {
		return 0
	}
	if reclaimLater != nil {
		for i := 0; i < len(reclaimLater); i++ {
			if reclaimLater[i] == n {
				reclaimLater[i] = nil
			}
		}
	}
	if n.next != reclaimable_node {
		return 0
	}
	var left *node
	var right *node
	if !n.left.isEmpty() {
		left = n.left.Node()
	}
	if !n.right.isEmpty() {
		right = n.right.Node()
	}
	t.freeNode_unlocked(n)
	numLeft := t.reclaimNodes_unlocked(left, reclaimLater)
	numRight := t.reclaimNodes_unlocked(right, reclaimLater)
	return 1 + numLeft + numRight
}

func numFreeNodes() int64 {
	freeNodeLock.Lock()
	defer freeNodeLock.Unlock()
	i := int64(0)
	for n := freeNodes; n != nil; n = n.next {
		i++
	}
	return i
}

// Assumes that the caller serializes invocations.
func (t *Collection) mkNode(itemIn *itemLoc, leftIn *nodeLoc, rightIn *nodeLoc,
	numNodesIn uint64, numBytesIn uint64) *node {
	freeNodeLock.Lock()
	freeStats.MkNodes++
	t.stats.MkNodes++
	n := freeNodes
	if n == nil {
		freeStats.AllocNodes++
		t.stats.AllocNodes++
		freeNodeLock.Unlock()
		atomic.AddUint64(&t.store.nodeAllocs, 1)
		n = &node{}
	} else {
		freeNodes = n.next
		freeNodeLock.Unlock()
	}
	n.item.Copy(itemIn)
	n.left.Copy(leftIn)
	n.right.Copy(rightIn)
	n.numNodes = numNodesIn
	n.numBytes = numBytesIn
	n.next = nil
	return n
}

func (t *Collection) freeNode_unlocked(n *node) {
	if n == nil || n == reclaimable_node {
		return
	}
	if n.next != nil && n.next != reclaimable_node {
		panic("double free node")
	}
	n.item = *empty_itemLoc
	n.left = *empty_nodeLoc
	n.right = *empty_nodeLoc
	n.numNodes = 0
	n.numBytes = 0

	n.next = freeNodes
	freeNodes = n
	freeStats.FreeNodes++
	t.stats.FreeNodes++
}

// Assumes that the caller serializes invocations.
func (t *Collection) mkNodeLoc(n *node) *nodeLoc {
	freeNodeLocLock.Lock()
	freeStats.MkNodeLocs++
	t.stats.MkNodeLocs++
	nloc := freeNodeLocs
	if nloc == nil {
		freeStats.AllocNodeLocs++
		t.stats.AllocNodeLocs++
		freeNodeLocLock.Unlock()
		nloc = &nodeLoc{}
	} else {
		freeNodeLocs = nloc.next
		freeNodeLocLock.Unlock()
	}
	nloc.loc = unsafe.Pointer(nil)
	nloc.node = unsafe.Pointer(n)
	nloc.next = nil
	return nloc
}

// Assumes that the caller serializes invocations.
func (t *Collection) freeNodeLoc(nloc *nodeLoc) {
	if nloc == nil || nloc == empty_nodeLoc {
		return
	}
	if nloc.next != nil {
		panic("double free nodeLoc")
	}
	nloc.loc = unsafe.Pointer(nil)
	nloc.node = unsafe.Pointer(nil)

	freeNodeLocLock.Lock()
	nloc.next = freeNodeLocs
	freeNodeLocs = nloc
	freeStats.FreeNodeLocs++
	t.stats.FreeNodeLocs++
	freeNodeLocLock.Unlock()
}

func (t *Collection) mkRootNodeLoc(root *nodeLoc) *rootNodeLoc {
	freeRootNodeLocLock.Lock()
	freeStats.MkRootNodeLocs++
	t.stats.MkRootNodeLocs++
	rnl := freeRootNodeLocs
	if rnl == nil {
		freeStats.AllocRootNodeLocs++
		t.stats.AllocRootNodeLocs++
		freeRootNodeLocLock.Unlock()
		rnl = &rootNodeLoc{}
	} else {
		freeRootNodeLocs = rnl.next
		freeRootNodeLocLock.Unlock()
	}
	rnl.refs = 1
	rnl.root = root
	rnl.next = nil
	rnl.chainedCollection = nil
	rnl.chainedRootNodeLoc = nil
	for i := 0; i < len(rnl.reclaimLater); i++ {
		rnl.reclaimLater[i] = nil
	}
	return rnl
}

func (t *Collection) freeRootNodeLoc(rnl *rootNodeLoc) {
	if rnl == nil {
		return
	}
	if rnl.next != nil {
		panic("double free rootNodeLoc")
	}
	rnl.refs = 0
	rnl.root = nil
	rnl.chainedCollection = nil
	rnl.chainedRootNodeLoc = nil
	for i := 0; i < len(rnl.reclaimLater); i++ {
		rnl.reclaimLater[i] = nil
	}
	freeRootNodeLocLock.Lock()
	rnl.next = freeRootNodeLocs
	freeRootNodeLocs = rnl
	freeStats.FreeRootNodeLocs++
	t.stats.FreeRootNodeLocs++
	freeRootNodeLocLock.Unlock()
}
<commit_msg>Track current free list lengths in freeStats.<commit_after>package gkvlite

import (
	"sync"
	"sync/atomic"
	"unsafe"
)

var reclaimable_node = &node{} // Sentinel.

var freeNodeLock sync.Mutex
var freeNodes *node

var freeNodeLocLock sync.Mutex
var freeNodeLocs *nodeLoc

var freeRootNodeLocLock sync.Mutex
var freeRootNodeLocs *rootNodeLoc

var freeStats FreeStats

type FreeStats struct {
	MkNodes      int64
	FreeNodes    int64 // Number of invocations of the freeNode() API.
	AllocNodes   int64
	CurFreeNodes int64 // Current length of freeNodes list.

	MkNodeLocs      int64
	FreeNodeLocs    int64 // Number of invocations of the freeNodeLoc() API.
	AllocNodeLocs   int64
	CurFreeNodeLocs int64 // Current length of freeNodeLocs list.

	MkRootNodeLocs      int64
	FreeRootNodeLocs    int64 // Number of invocations of the freeRootNodeLoc() API.
	AllocRootNodeLocs   int64
	CurFreeRootNodeLocs int64 // Current length of freeRootNodeLocs list.
}

func (t *Collection) markReclaimable(n *node) {
	t.rootLock.Lock()
	defer t.rootLock.Unlock()
	if n == nil || n.next != nil || n == reclaimable_node {
		return
	}
	n.next = reclaimable_node // Use next pointer as sentinel.
}

func (t *Collection) reclaimNodes_unlocked(n *node, reclaimLater *[2]*node) int64 {
	if n == nil {
		return 0
	}
	if reclaimLater != nil {
		for i := 0; i < len(reclaimLater); i++ {
			if reclaimLater[i] == n {
				reclaimLater[i] = nil
			}
		}
	}
	if n.next != reclaimable_node {
		return 0
	}
	var left *node
	var right *node
	if !n.left.isEmpty() {
		left = n.left.Node()
	}
	if !n.right.isEmpty() {
		right = n.right.Node()
	}
	t.freeNode_unlocked(n)
	numLeft := t.reclaimNodes_unlocked(left, reclaimLater)
	numRight := t.reclaimNodes_unlocked(right, reclaimLater)
	return 1 + numLeft + numRight
}

func numFreeNodes() int64 {
	freeNodeLock.Lock()
	defer freeNodeLock.Unlock()
	i := int64(0)
	for n := freeNodes; n != nil; n = n.next {
		i++
	}
	return i
}

// Assumes that the caller serializes invocations.
func (t *Collection) mkNode(itemIn *itemLoc, leftIn *nodeLoc, rightIn *nodeLoc,
	numNodesIn uint64, numBytesIn uint64) *node {
	freeNodeLock.Lock()
	freeStats.MkNodes++
	t.stats.MkNodes++
	n := freeNodes
	if n == nil {
		freeStats.AllocNodes++
		t.stats.AllocNodes++
		freeNodeLock.Unlock()
		atomic.AddUint64(&t.store.nodeAllocs, 1)
		n = &node{}
	} else {
		freeNodes = n.next
		freeStats.CurFreeNodes--
		freeNodeLock.Unlock()
	}
	n.item.Copy(itemIn)
	n.left.Copy(leftIn)
	n.right.Copy(rightIn)
	n.numNodes = numNodesIn
	n.numBytes = numBytesIn
	n.next = nil
	return n
}

func (t *Collection) freeNode_unlocked(n *node) {
	if n == nil || n == reclaimable_node {
		return
	}
	if n.next != nil && n.next != reclaimable_node {
		panic("double free node")
	}
	n.item = *empty_itemLoc
	n.left = *empty_nodeLoc
	n.right = *empty_nodeLoc
	n.numNodes = 0
	n.numBytes = 0

	n.next = freeNodes
	freeNodes = n
	freeStats.CurFreeNodes++
	freeStats.FreeNodes++
	t.stats.FreeNodes++
}

// Assumes that the caller serializes invocations.
func (t *Collection) mkNodeLoc(n *node) *nodeLoc {
	freeNodeLocLock.Lock()
	freeStats.MkNodeLocs++
	t.stats.MkNodeLocs++
	nloc := freeNodeLocs
	if nloc == nil {
		freeStats.AllocNodeLocs++
		t.stats.AllocNodeLocs++
		freeNodeLocLock.Unlock()
		nloc = &nodeLoc{}
	} else {
		freeNodeLocs = nloc.next
		freeStats.CurFreeNodeLocs--
		freeNodeLocLock.Unlock()
	}
	nloc.loc = unsafe.Pointer(nil)
	nloc.node = unsafe.Pointer(n)
	nloc.next = nil
	return nloc
}

// Assumes that the caller serializes invocations.
func (t *Collection) freeNodeLoc(nloc *nodeLoc) {
	if nloc == nil || nloc == empty_nodeLoc {
		return
	}
	if nloc.next != nil {
		panic("double free nodeLoc")
	}
	nloc.loc = unsafe.Pointer(nil)
	nloc.node = unsafe.Pointer(nil)

	freeNodeLocLock.Lock()
	nloc.next = freeNodeLocs
	freeNodeLocs = nloc
	freeStats.CurFreeNodeLocs++
	freeStats.FreeNodeLocs++
	t.stats.FreeNodeLocs++
	freeNodeLocLock.Unlock()
}

func (t *Collection) mkRootNodeLoc(root *nodeLoc) *rootNodeLoc {
	freeRootNodeLocLock.Lock()
	freeStats.MkRootNodeLocs++
	t.stats.MkRootNodeLocs++
	rnl := freeRootNodeLocs
	if rnl == nil {
		freeStats.AllocRootNodeLocs++
		t.stats.AllocRootNodeLocs++
		freeRootNodeLocLock.Unlock()
		rnl = &rootNodeLoc{}
	} else {
		freeRootNodeLocs = rnl.next
		freeStats.CurFreeRootNodeLocs--
		freeRootNodeLocLock.Unlock()
	}
	rnl.refs = 1
	rnl.root = root
	rnl.next = nil
	rnl.chainedCollection = nil
	rnl.chainedRootNodeLoc = nil
	for i := 0; i < len(rnl.reclaimLater); i++ {
		rnl.reclaimLater[i] = nil
	}
	return rnl
}

func (t *Collection) freeRootNodeLoc(rnl *rootNodeLoc) {
	if rnl == nil {
		return
	}
	if rnl.next != nil {
		panic("double free rootNodeLoc")
	}
	rnl.refs = 0
	rnl.root = nil
	rnl.chainedCollection = nil
	rnl.chainedRootNodeLoc = nil
	for i := 0; i < len(rnl.reclaimLater); i++ {
		rnl.reclaimLater[i] = nil
	}
	freeRootNodeLocLock.Lock()
	rnl.next = freeRootNodeLocs
	freeRootNodeLocs = rnl
	freeStats.CurFreeRootNodeLocs++
	freeStats.FreeRootNodeLocs++
	t.stats.FreeRootNodeLocs++
	freeRootNodeLocLock.Unlock()
}
<|endoftext|>