<commit_before>/*
   Copyright (c) 2014, Percona LLC and/or its affiliates. All rights reserved.

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>
*/

package instance

import (
	"encoding/json"
	"errors"
	"fmt"
	"strings"

	"github.com/percona/percona-agent/agent"

	"strconv"

	"github.com/percona/cloud-protocol/proto"
	"github.com/percona/percona-agent/mrms"
	"github.com/percona/percona-agent/mrms/monitor"
	"github.com/percona/percona-agent/mysql"
	"github.com/percona/percona-agent/pct"
)

type empty struct{}

type Manager struct {
	logger    *pct.Logger
	configDir string
	api       pct.APIConnector
	// --
	status         *pct.Status
	repo           *Repo
	stopChan       chan empty
	mrm            mrms.Monitor
	mrmChans       map[string]<-chan bool
	mrmsGlobalChan chan string
	agentConfig    *agent.Config
}

func NewManager(logger *pct.Logger, configDir string, api pct.APIConnector, mrm mrms.Monitor, conf *agent.Config) *Manager {
	repo := NewRepo(pct.NewLogger(logger.LogChan(), "instance-repo"), configDir, api)
	m := &Manager{
		logger:    logger,
		configDir: configDir,
		api:       api,
		// --
		status:         pct.NewStatus([]string{"instance", "instance-repo"}),
		repo:           repo,
		mrm:            mrm,
		mrmChans:       make(map[string]<-chan bool),
		mrmsGlobalChan: make(chan string, 100), // monitor up to 100 instances
		agentConfig:    conf,
	}
	return m
}

/////////////////////////////////////////////////////////////////////////////
// Interface
/////////////////////////////////////////////////////////////////////////////

// @goroutine[0]
func (m *Manager) Start() error {
	m.status.Update("instance", "Starting")
	if err := m.repo.Init(); err != nil {
		return err
	}
	m.logger.Info("Started")
	m.status.Update("instance", "Running")

	mrm := m.mrm.(*monitor.Monitor)
	mrmsGlobalChan, err := mrm.GlobalSubscribe()
	if err != nil {
		return err
	}
	instances, err := m.getMySQLInstances()
	if err != nil {
		return err
	}
	for _, instance := range instances {
		ch, err := m.mrm.Add(instance.DSN)
		if err == nil {
			// Store the channel to be able to remove it from mrms
			m.mrmChans[instance.DSN] = ch
		}
	}
	go m.monitorInstancesRestart(mrmsGlobalChan)
	return nil
}

// @goroutine[0]
func (m *Manager) Stop() error {
	// Can't stop the instance manager.
	return nil
}

// @goroutine[0]
func (m *Manager) Handle(cmd *proto.Cmd) *proto.Reply {
	m.status.UpdateRe("instance", "Handling", cmd)
	defer m.status.Update("instance", "Running")

	it := &proto.ServiceInstance{}
	if err := json.Unmarshal(cmd.Data, it); err != nil {
		return cmd.Reply(nil, err)
	}

	switch cmd.Cmd {
	case "Add":
		err := m.repo.Add(it.Service, it.InstanceId, it.Instance, true) // true = write to disk
		/*
			if it.Service == "mysql" {
				// Get the instance as type proto.MySQLInstance instead of proto.ServiceInstance
				// because we need the dsn field
				iit := &proto.MySQLInstance{}
				err := m.repo.Get(it.Service, it.InstanceId, iit)
				if err != nil {
					return cmd.Reply(nil, err)
				}
				if err != nil {
					return cmd.Reply(nil, err)
				}
				ch, err := m.mrm.Add(iit.DSN)
				if err != nil {
					m.mrmChans[iit.DSN] = ch
				}
			}
		*/
		return cmd.Reply(nil, err)
	case "Remove":
		err := m.repo.Remove(it.Service, it.InstanceId)
		if it.Service == "mysql" {
			// Get the instance as type proto.MySQLInstance instead of proto.ServiceInstance
			// because we need the dsn field
			iit := &proto.MySQLInstance{}
			err := m.repo.Get(it.Service, it.InstanceId, iit)
			if err != nil {
				return cmd.Reply(nil, err)
			}
			if err != nil {
				return cmd.Reply(nil, err)
			}
			m.mrm.Remove(iit.DSN, m.mrmChans[iit.DSN])
		}
		return cmd.Reply(nil, err)
	case "GetInfo":
		info, err := m.handleGetInfo(it.Service, it.Instance)
		return cmd.Reply(info, err)
	default:
		return cmd.Reply(nil, pct.UnknownCmdError{Cmd: cmd.Cmd})
	}
}

func (m *Manager) Status() map[string]string {
	m.status.Update("instance-repo", strings.Join(m.repo.List(), " "))
	return m.status.All()
}

func (m *Manager) GetConfig() ([]proto.AgentConfig, []error) {
	return nil, nil
}

func (m *Manager) Repo() *Repo {
	return m.repo
}

/////////////////////////////////////////////////////////////////////////////
// Implementation
/////////////////////////////////////////////////////////////////////////////

func (m *Manager) handleGetInfo(service string, data []byte) (interface{}, error) {
	switch service {
	case "mysql":
		it := &proto.MySQLInstance{}
		if err := json.Unmarshal(data, it); err != nil {
			return nil, errors.New("instance.Repo:json.Unmarshal:" + err.Error())
		}
		if it.DSN == "" {
			return nil, fmt.Errorf("MySQL instance DSN is not set")
		}
		if err := GetMySQLInfo(it); err != nil {
			return nil, err
		}
		return it, nil
	default:
		return nil, fmt.Errorf("Don't know how to get info for %s service", service)
	}
}

func GetMySQLInfo(it *proto.MySQLInstance) error {
	conn := mysql.NewConnection(it.DSN)
	if err := conn.Connect(1); err != nil {
		return err
	}
	sql := "SELECT /* percona-agent */" +
		" CONCAT_WS('.', @@hostname, IF(@@port='3306',NULL,@@port)) AS Hostname," +
		" @@version_comment AS Distro," +
		" @@version AS Version"
	err := conn.DB().QueryRow(sql).Scan(
		&it.Hostname,
		&it.Distro,
		&it.Version,
	)
	if err != nil {
		return err
	}
	conn.Close()
	return nil
}

func (m *Manager) getMySQLInstances() ([]*proto.MySQLInstance, error) {
	var instances []*proto.MySQLInstance
	for _, name := range m.Repo().List() {
		parts := strings.Split(name, "-") // mysql-1 or server-12
		if len(parts) != 2 {
			return nil, fmt.Errorf("Invalid instance name: %+v", name)
		}
		if parts[0] == "mysql" {
			id, err := strconv.ParseInt(parts[1], 10, 64)
			if err != nil {
				return nil, err
			}
			it := &proto.MySQLInstance{}
			err = m.Repo().Get(parts[0], uint(id), it)
			if err != nil {
				return nil, err
			}
			err = GetMySQLInfo(it)
			instances = append(instances, it)
		}
	}
	return instances, nil
}

func (m *Manager) monitorInstancesRestart(ch chan string) {
	// Cast mrms monitor as its real type and not the interface
	// because the interface doesn't implements GlobalSubscribe()
	mm := m.mrm.(*monitor.Monitor)
	ch, err := mm.GlobalSubscribe()
	if err != nil {
		m.status.Update("monitorInstancesRestart", fmt.Sprintf("Error %v", err))
	}

	for {
		dsn := <-ch
		// Get the updated instances list. It should be updated every time since
		// the Add method can add new instances to the list
		instances, err := m.getMySQLInstances()
		if err != nil {
			m.status.Update("instance manager", fmt.Sprintf("Error in Global Instance Monitor: %v", err.Error()))
		}
		for _, instance := range instances {
			if instance.DSN == dsn {
				GetMySQLInfo(instance)
				uri := pct.URL(m.agentConfig.ApiHostname, "instances", "mysql", fmt.Sprintf("%d", instance.Id))
				data, err := json.Marshal(instance)
				if err != nil {
					m.status.Update("monitorInstancesRestart", err.Error())
					continue
				}
				m.api.Put(m.api.ApiKey(), uri, data)
			}
		}
	}
}
<commit_msg>PCT-562<commit_after>/*
   Copyright (c) 2014, Percona LLC and/or its affiliates. All rights reserved.

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>
*/

package instance

import (
	"encoding/json"
	"errors"
	"fmt"
	"strings"

	"github.com/percona/percona-agent/agent"

	"strconv"

	"github.com/percona/cloud-protocol/proto"
	"github.com/percona/percona-agent/mrms"
	"github.com/percona/percona-agent/mrms/monitor"
	"github.com/percona/percona-agent/mysql"
	"github.com/percona/percona-agent/pct"
)

type empty struct{}

type Manager struct {
	logger    *pct.Logger
	configDir string
	api       pct.APIConnector
	// --
	status         *pct.Status
	repo           *Repo
	stopChan       chan empty
	mrm            mrms.Monitor
	mrmChans       map[string]<-chan bool
	mrmsGlobalChan chan string
	agentConfig    *agent.Config
}

func NewManager(logger *pct.Logger, configDir string, api pct.APIConnector, mrm mrms.Monitor, conf *agent.Config) *Manager {
	repo := NewRepo(pct.NewLogger(logger.LogChan(), "instance-repo"), configDir, api)
	m := &Manager{
		logger:    logger,
		configDir: configDir,
		api:       api,
		// --
		status:         pct.NewStatus([]string{"instance", "instance-repo"}),
		repo:           repo,
		mrm:            mrm,
		mrmChans:       make(map[string]<-chan bool),
		mrmsGlobalChan: make(chan string, 100), // monitor up to 100 instances
		agentConfig:    conf,
	}
	return m
}

/////////////////////////////////////////////////////////////////////////////
// Interface
/////////////////////////////////////////////////////////////////////////////

// @goroutine[0]
func (m *Manager) Start() error {
	m.status.Update("instance", "Starting")
	if err := m.repo.Init(); err != nil {
		return err
	}
	m.logger.Info("Started")
	m.status.Update("instance", "Running")

	mrm := m.mrm.(*monitor.Monitor)
	mrmsGlobalChan, err := mrm.GlobalSubscribe()
	if err != nil {
		return err
	}
	instances, err := m.getMySQLInstances()
	if err != nil {
		return err
	}
	for _, instance := range instances {
		ch, err := m.mrm.Add(instance.DSN)
		if err == nil {
			// Store the channel to be able to remove it from mrms
			m.mrmChans[instance.DSN] = ch
		}
	}
	go m.monitorInstancesRestart(mrmsGlobalChan)
	return nil
}

// @goroutine[0]
func (m *Manager) Stop() error {
	// Can't stop the instance manager.
	return nil
}

// @goroutine[0]
func (m *Manager) Handle(cmd *proto.Cmd) *proto.Reply {
	m.status.UpdateRe("instance", "Handling", cmd)
	defer m.status.Update("instance", "Running")

	it := &proto.ServiceInstance{}
	if err := json.Unmarshal(cmd.Data, it); err != nil {
		return cmd.Reply(nil, err)
	}

	switch cmd.Cmd {
	case "Add":
		err := m.repo.Add(it.Service, it.InstanceId, it.Instance, true) // true = write to disk
		if it.Service == "mysql" {
			// Get the instance as type proto.MySQLInstance instead of proto.ServiceInstance
			// because we need the dsn field
			iit := &proto.MySQLInstance{}
			err := m.repo.Get(it.Service, it.InstanceId, iit)
			if err != nil {
				return cmd.Reply(nil, err)
			}
			if err != nil {
				return cmd.Reply(nil, err)
			}
			ch, err := m.mrm.Add(iit.DSN)
			if err != nil {
				m.mrmChans[iit.DSN] = ch
			}
		}
		return cmd.Reply(nil, err)
	case "Remove":
		err := m.repo.Remove(it.Service, it.InstanceId)
		if it.Service == "mysql" {
			// Get the instance as type proto.MySQLInstance instead of proto.ServiceInstance
			// because we need the dsn field
			iit := &proto.MySQLInstance{}
			err := m.repo.Get(it.Service, it.InstanceId, iit)
			if err != nil {
				return cmd.Reply(nil, err)
			}
			if err != nil {
				return cmd.Reply(nil, err)
			}
			m.mrm.Remove(iit.DSN, m.mrmChans[iit.DSN])
		}
		return cmd.Reply(nil, err)
	case "GetInfo":
		info, err := m.handleGetInfo(it.Service, it.Instance)
		return cmd.Reply(info, err)
	default:
		return cmd.Reply(nil, pct.UnknownCmdError{Cmd: cmd.Cmd})
	}
}

func (m *Manager) Status() map[string]string {
	m.status.Update("instance-repo", strings.Join(m.repo.List(), " "))
	return m.status.All()
}

func (m *Manager) GetConfig() ([]proto.AgentConfig, []error) {
	return nil, nil
}

func (m *Manager) Repo() *Repo {
	return m.repo
}

/////////////////////////////////////////////////////////////////////////////
// Implementation
/////////////////////////////////////////////////////////////////////////////

func (m *Manager) handleGetInfo(service string, data []byte) (interface{}, error) {
	switch service {
	case "mysql":
		it := &proto.MySQLInstance{}
		if err := json.Unmarshal(data, it); err != nil {
			return nil, errors.New("instance.Repo:json.Unmarshal:" + err.Error())
		}
		if it.DSN == "" {
			return nil, fmt.Errorf("MySQL instance DSN is not set")
		}
		if err := GetMySQLInfo(it); err != nil {
			return nil, err
		}
		return it, nil
	default:
		return nil, fmt.Errorf("Don't know how to get info for %s service", service)
	}
}

func GetMySQLInfo(it *proto.MySQLInstance) error {
	conn := mysql.NewConnection(it.DSN)
	if err := conn.Connect(1); err != nil {
		return err
	}
	sql := "SELECT /* percona-agent */" +
		" CONCAT_WS('.', @@hostname, IF(@@port='3306',NULL,@@port)) AS Hostname," +
		" @@version_comment AS Distro," +
		" @@version AS Version"
	err := conn.DB().QueryRow(sql).Scan(
		&it.Hostname,
		&it.Distro,
		&it.Version,
	)
	if err != nil {
		return err
	}
	conn.Close()
	return nil
}

func (m *Manager) getMySQLInstances() ([]*proto.MySQLInstance, error) {
	var instances []*proto.MySQLInstance
	for _, name := range m.Repo().List() {
		parts := strings.Split(name, "-") // mysql-1 or server-12
		if len(parts) != 2 {
			return nil, fmt.Errorf("Invalid instance name: %+v", name)
		}
		if parts[0] == "mysql" {
			id, err := strconv.ParseInt(parts[1], 10, 64)
			if err != nil {
				return nil, err
			}
			it := &proto.MySQLInstance{}
			err = m.Repo().Get(parts[0], uint(id), it)
			if err != nil {
				return nil, err
			}
			err = GetMySQLInfo(it)
			instances = append(instances, it)
		}
	}
	return instances, nil
}

func (m *Manager) monitorInstancesRestart(ch chan string) {
	// Cast mrms monitor as its real type and not the interface
	// because the interface doesn't implements GlobalSubscribe()
	mm := m.mrm.(*monitor.Monitor)
	ch, err := mm.GlobalSubscribe()
	if err != nil {
		m.status.Update("monitorInstancesRestart", fmt.Sprintf("Error %v", err))
	}

	for {
		dsn := <-ch
		// Get the updated instances list. It should be updated every time since
		// the Add method can add new instances to the list
		instances, err := m.getMySQLInstances()
		if err != nil {
			m.status.Update("instance manager", fmt.Sprintf("Error in Global Instance Monitor: %v", err.Error()))
		}
		for _, instance := range instances {
			if instance.DSN == dsn {
				GetMySQLInfo(instance)
				uri := pct.URL(m.agentConfig.ApiHostname, "instances", "mysql", fmt.Sprintf("%d", instance.Id))
				data, err := json.Marshal(instance)
				if err != nil {
					m.status.Update("monitorInstancesRestart", err.Error())
					continue
				}
				m.api.Put(m.api.ApiKey(), uri, data)
			}
		}
	}
}
<|endoftext|>


<commit_before>//+build integration

package ddtracer

import (
	"math/rand"
	"testing"
	"time"

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

func spanChild(tr opentracing.Tracer, parent opentracing.Span, op string) opentracing.Span {
	time.Sleep(time.Duration(rand.Intn(500)) * time.Millisecond)
	child := tr.StartSpan("child", opentracing.ChildOf(parent.Context()))
	time.Sleep(time.Duration(rand.Intn(500)) * time.Millisecond)
	return child
}

func TestIntegration(t *testing.T) {
	tr := NewTracer()
	tr.(*Tracer).DebugLoggingEnabled = true

	parent := tr.StartSpan("parent")
	parent.LogKV("foo", "bar", "ping", 0.546)
	time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)

	spanChild(tr, parent, "child1").Finish()
	spanChild(tr, parent, "child2").Finish()
	parent.Finish()

	select {}

}
<commit_msg>Update integration test<commit_after>//+build integration

package ddtracer

import (
	"math/rand"
	"testing"
	"time"

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

func spanChild(tr opentracing.Tracer, parent opentracing.Span, op string) opentracing.Span {
	time.Sleep(time.Duration(rand.Intn(500)) * time.Millisecond)
	span := tr.StartSpan("child",
		opentracing.ChildOf(parent.Context()),
		opentracing.Tag{ServiceTagKey, "gochild"},
	)
	time.Sleep(time.Duration(rand.Intn(500)) * time.Millisecond)
	return span
}

func TestIntegration(t *testing.T) {
	tr := NewTracer()
	tr.(*Tracer).DebugLoggingEnabled = true

	parent := tr.StartSpan("parent",
		opentracing.Tag{ServiceTagKey, "gotest"},
		opentracing.Tag{ResourceTagKey, "/user/{id}"},
	)
	parent.LogKV("foo", "bar", "ping", 0.546)

	spanChild(tr, parent, "child1").Finish()
	child := spanChild(tr, parent, "child2")
	parent.Finish()
	time.Sleep(time.Duration(rand.Intn(300)) * time.Millisecond)
	child.Finish()

	select {}

}
<|endoftext|>


<commit_before>package containerd

import (
	"context"
	"time"

	"github.com/containerd/containerd/content"
	"github.com/containerd/containerd/mount"
	"github.com/containerd/containerd/namespaces"
	ctdsnapshot "github.com/containerd/containerd/snapshots"
	"github.com/moby/buildkit/cache/metadata"
	"github.com/moby/buildkit/snapshot"
	"github.com/moby/buildkit/snapshot/blobmapping"
)

func NewSnapshotter(snapshotter ctdsnapshot.Snapshotter, store content.Store, mdstore *metadata.Store, ns string, gc func(context.Context) error) snapshot.Snapshotter {
	return blobmapping.NewSnapshotter(blobmapping.Opt{
		Content:       store,
		Snapshotter:   &nsSnapshotter{ns, snapshotter, gc},
		MetadataStore: mdstore,
	})
}

type nsSnapshotter struct {
	ns string
	ctdsnapshot.Snapshotter
	gc garbageCollectFn
}

func (s *nsSnapshotter) Stat(ctx context.Context, key string) (ctdsnapshot.Info, error) {
	ctx = namespaces.WithNamespace(ctx, s.ns)
	return s.Snapshotter.Stat(ctx, key)
}

func (s *nsSnapshotter) Update(ctx context.Context, info ctdsnapshot.Info, fieldpaths ...string) (ctdsnapshot.Info, error) {
	ctx = namespaces.WithNamespace(ctx, s.ns)
	return s.Snapshotter.Update(ctx, info, fieldpaths...)
}

func (s *nsSnapshotter) Usage(ctx context.Context, key string) (ctdsnapshot.Usage, error) {
	ctx = namespaces.WithNamespace(ctx, s.ns)
	return s.Snapshotter.Usage(ctx, key)
}
func (s *nsSnapshotter) Mounts(ctx context.Context, key string) ([]mount.Mount, error) {
	ctx = namespaces.WithNamespace(ctx, s.ns)
	return s.Snapshotter.Mounts(ctx, key)
}
func (s *nsSnapshotter) Prepare(ctx context.Context, key, parent string, opts ...ctdsnapshot.Opt) ([]mount.Mount, error) {
	ctx = namespaces.WithNamespace(ctx, s.ns)
	return s.Snapshotter.Prepare(ctx, key, parent, addRootLabel(opts...))
}
func (s *nsSnapshotter) View(ctx context.Context, key, parent string, opts ...ctdsnapshot.Opt) ([]mount.Mount, error) {
	ctx = namespaces.WithNamespace(ctx, s.ns)
	return s.Snapshotter.View(ctx, key, parent, addRootLabel(opts...))
}
func (s *nsSnapshotter) Commit(ctx context.Context, name, key string, opts ...ctdsnapshot.Opt) error {
	ctx = namespaces.WithNamespace(ctx, s.ns)
	return s.Snapshotter.Commit(ctx, name, key, addRootLabel(opts...))
}
func (s *nsSnapshotter) Remove(ctx context.Context, key string) error {
	ctx = namespaces.WithNamespace(ctx, s.ns)
	if _, err := s.Update(ctx, ctdsnapshot.Info{
		Name: key,
	}, "labels.containerd.io/gc.root"); err != nil {
		return err
	} // calling snapshotter.Remove here causes a race in containerd
	if s.gc == nil {
		return nil
	}
	return s.gc(ctx)
}
func (s *nsSnapshotter) Walk(ctx context.Context, fn func(context.Context, ctdsnapshot.Info) error) error {
	ctx = namespaces.WithNamespace(ctx, s.ns)
	return s.Snapshotter.Walk(ctx, fn)
}

func addRootLabel(opts ...ctdsnapshot.Opt) ctdsnapshot.Opt {
	return func(info *ctdsnapshot.Info) error {
		for _, opt := range opts {
			if err := opt(info); err != nil {
				return err
			}
		}
		if info.Labels == nil {
			info.Labels = map[string]string{}
		}
		info.Labels["containerd.io/gc.root"] = time.Now().UTC().Format(time.RFC3339Nano)
		return nil
	}
}
<commit_msg>snapshotter: avoid snapshot removal race<commit_after>package containerd

import (
	"context"
	"time"

	"github.com/containerd/containerd/content"
	"github.com/containerd/containerd/mount"
	"github.com/containerd/containerd/namespaces"
	ctdsnapshot "github.com/containerd/containerd/snapshots"
	"github.com/moby/buildkit/cache/metadata"
	"github.com/moby/buildkit/snapshot"
	"github.com/moby/buildkit/snapshot/blobmapping"
)

func NewSnapshotter(snapshotter ctdsnapshot.Snapshotter, store content.Store, mdstore *metadata.Store, ns string, gc func(context.Context) error) snapshot.Snapshotter {
	return blobmapping.NewSnapshotter(blobmapping.Opt{
		Content:       store,
		Snapshotter:   &nsSnapshotter{ns, snapshotter, gc},
		MetadataStore: mdstore,
	})
}

type nsSnapshotter struct {
	ns string
	ctdsnapshot.Snapshotter
	gc garbageCollectFn
}

func (s *nsSnapshotter) Stat(ctx context.Context, key string) (ctdsnapshot.Info, error) {
	ctx = namespaces.WithNamespace(ctx, s.ns)
	info, err := s.Snapshotter.Stat(ctx, key)
	if err == nil {
		if _, ok := info.Labels["labels.containerd.io/gc.root"]; !ok {
			if err := addRootLabel()(&info); err != nil {
				return info, err
			}
			return s.Update(ctx, info, "labels.containerd.io/gc.root")
		}
	}
	return info, err
}

func (s *nsSnapshotter) Update(ctx context.Context, info ctdsnapshot.Info, fieldpaths ...string) (ctdsnapshot.Info, error) {
	ctx = namespaces.WithNamespace(ctx, s.ns)
	return s.Snapshotter.Update(ctx, info, fieldpaths...)
}

func (s *nsSnapshotter) Usage(ctx context.Context, key string) (ctdsnapshot.Usage, error) {
	ctx = namespaces.WithNamespace(ctx, s.ns)
	return s.Snapshotter.Usage(ctx, key)
}
func (s *nsSnapshotter) Mounts(ctx context.Context, key string) ([]mount.Mount, error) {
	ctx = namespaces.WithNamespace(ctx, s.ns)
	return s.Snapshotter.Mounts(ctx, key)
}
func (s *nsSnapshotter) Prepare(ctx context.Context, key, parent string, opts ...ctdsnapshot.Opt) ([]mount.Mount, error) {
	ctx = namespaces.WithNamespace(ctx, s.ns)
	return s.Snapshotter.Prepare(ctx, key, parent, addRootLabel(opts...))
}
func (s *nsSnapshotter) View(ctx context.Context, key, parent string, opts ...ctdsnapshot.Opt) ([]mount.Mount, error) {
	ctx = namespaces.WithNamespace(ctx, s.ns)
	return s.Snapshotter.View(ctx, key, parent, addRootLabel(opts...))
}
func (s *nsSnapshotter) Commit(ctx context.Context, name, key string, opts ...ctdsnapshot.Opt) error {
	ctx = namespaces.WithNamespace(ctx, s.ns)
	return s.Snapshotter.Commit(ctx, name, key, addRootLabel(opts...))
}
func (s *nsSnapshotter) Remove(ctx context.Context, key string) error {
	ctx = namespaces.WithNamespace(ctx, s.ns)
	if _, err := s.Update(ctx, ctdsnapshot.Info{
		Name: key,
	}, "labels.containerd.io/gc.root"); err != nil {
		return err
	} // calling snapshotter.Remove here causes a race in containerd
	if s.gc == nil {
		return nil
	}
	return s.gc(ctx)
}
func (s *nsSnapshotter) Walk(ctx context.Context, fn func(context.Context, ctdsnapshot.Info) error) error {
	ctx = namespaces.WithNamespace(ctx, s.ns)
	return s.Snapshotter.Walk(ctx, fn)
}

func addRootLabel(opts ...ctdsnapshot.Opt) ctdsnapshot.Opt {
	return func(info *ctdsnapshot.Info) error {
		for _, opt := range opts {
			if err := opt(info); err != nil {
				return err
			}
		}
		if info.Labels == nil {
			info.Labels = map[string]string{}
		}
		info.Labels["containerd.io/gc.root"] = time.Now().UTC().Format(time.RFC3339Nano)
		return nil
	}
}
<|endoftext|>


<commit_before>package integrations

import (
	"github.com/chrisledet/rebasebot/git"
	"github.com/chrisledet/rebasebot/github"
)

// Ties the git operations together to perform a branch rebase
func GitRebase(pr *github.PullRequest) error {
	filepath := git.GetRepositoryFilePath(pr.Head.Repository.FullName)
	remoteRepositoryURL := git.GenerateCloneURL(pr.Head.Repository.FullName)

	if !git.Exists(filepath) {
		if _, err := git.Clone(remoteRepositoryURL); err != nil {
			pr.PostComment("I could not pull " + pr.Head.Repository.FullName + " from GitHub.")
			return err
		}
	}

	if err := git.Fetch(filepath); err != nil {
		pr.PostComment("I could not fetch the latest changes from GitHub.")
		return err
	}

	if err := git.Checkout(filepath, pr.Head.Ref); err != nil {
		pr.PostComment("I could not checkout " + pr.Head.Ref + " locally.")
		return err
	}

	if err := git.Reset(filepath, pr.Head.Ref); err != nil {
		pr.PostComment("I could not checkout " + pr.Head.Ref + " locally.")
		return err
	}

	if err := git.Rebase(filepath, pr.Base.Ref); err != nil {
		pr.PostComment("I could not rebase " + pr.Head.Ref + " with " + pr.Base.Ref + ". There are conflicts.")
		return err
	}

	if err := git.Push(filepath, pr.Head.Ref); err != nil {
		pr.PostComment("I could not push the changes to " + pr.Base.Ref + ".")
		return err
	}

	pr.PostComment("I just pushed up the changes, enjoy!")
	return nil
}
<commit_msg>Make sure we're always rebasing with the latest<commit_after>package integrations

import (
	"github.com/chrisledet/rebasebot/git"
	"github.com/chrisledet/rebasebot/github"
	"path"
)

// Ties the git operations together to perform a branch rebase
func GitRebase(pr *github.PullRequest) error {
	filepath := git.GetRepositoryFilePath(pr.Head.Repository.FullName)
	remoteRepositoryURL := git.GenerateCloneURL(pr.Head.Repository.FullName)

	if !git.Exists(filepath) {
		if _, err := git.Clone(remoteRepositoryURL); err != nil {
			pr.PostComment("I could not pull " + pr.Head.Repository.FullName + " from GitHub.")
			return err
		}
	}

	if err := git.Fetch(filepath); err != nil {
		pr.PostComment("I could not fetch the latest changes from GitHub.")
		return err
	}

	if err := git.Checkout(filepath, pr.Head.Ref); err != nil {
		pr.PostComment("I could not checkout " + pr.Head.Ref + " locally.")
		return err
	}

	if err := git.Reset(filepath, path.Join("origin", pr.Head.Ref)); err != nil {
		pr.PostComment("I could not checkout " + pr.Head.Ref + " locally.")
		return err
	}

	if err := git.Rebase(filepath, path.Join("origin", pr.Base.Ref)); err != nil {
		pr.PostComment("I could not rebase " + pr.Head.Ref + " with " + pr.Base.Ref + ". There are conflicts.")
		return err
	}

	if err := git.Push(filepath, pr.Head.Ref); err != nil {
		pr.PostComment("I could not push the changes to " + pr.Base.Ref + ".")
		return err
	}

	pr.PostComment("I just pushed up the changes, enjoy!")
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2011 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 types

import (
	"exec"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"testing"
	"time"
)

var gcName, gcPath string // compiler name and path

func init() {
	// find a compiler
	for _, char := range []string{"5", "6", "8"} {
		var err os.Error
		gcName = char + "g"
		gcPath, err = exec.LookPath(gcName)
		if err == nil {
			return
		}
	}
}

func compile(t *testing.T, dirname, filename string) {
	cmd, err := exec.Run(gcPath, []string{gcPath, filename}, nil, dirname, exec.DevNull, exec.Pipe, exec.MergeWithStdout)
	if err != nil {
		t.Errorf("%s %s failed: %s", gcName, filename, err)
		return
	}
	defer cmd.Close()

	msg, err := cmd.Wait(0)
	if err != nil {
		t.Errorf("%s %s failed: %s", gcName, filename, err)
		return
	}

	if !msg.Exited() || msg.ExitStatus() != 0 {
		t.Errorf("%s %s failed: exit status = %d", gcName, filename, msg.ExitStatus())
		output, _ := ioutil.ReadAll(cmd.Stdout)
		t.Log(string(output))
	}
}

func testPath(t *testing.T, path string) bool {
	_, _, err := GcImporter(path)
	if err != nil {
		t.Errorf("testPath(%s): %s", path, err)
		return false
	}
	return true
}

const maxTime = 3e9 // maximum allotted testing time in ns

func testDir(t *testing.T, dir string, endTime int64) (nimports int) {
	dirname := filepath.Join(pkgRoot, dir)
	list, err := ioutil.ReadDir(dirname)
	if err != nil {
		t.Errorf("testDir(%s): %s", dirname, err)
	}
	for _, f := range list {
		if time.Nanoseconds() >= endTime {
			t.Log("testing time used up")
			return
		}
		switch {
		case f.IsRegular():
			// try extensions
			for _, ext := range pkgExts {
				if strings.HasSuffix(f.Name, ext) {
					name := f.Name[0 : len(f.Name)-len(ext)] // remove extension
					if testPath(t, filepath.Join(dir, name)) {
						nimports++
					}
				}
			}
		case f.IsDirectory():
			nimports += testDir(t, filepath.Join(dir, f.Name), endTime)
		}
	}
	return
}

func TestGcImport(t *testing.T) {
	compile(t, "testdata", "exports.go")

	nimports := 0
	if testPath(t, "./testdata/exports") {
		nimports++
	}
	nimports += testDir(t, "", time.Nanoseconds()+maxTime) // installed packages
	t.Logf("tested %d imports", nimports)
}
<commit_msg>go/types: fix build: use the right compiler to compile test case<commit_after>// Copyright 2011 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 types

import (
	"exec"
	"io/ioutil"
	"path/filepath"
	"runtime"
	"strings"
	"testing"
	"time"
)

var gcName, gcPath string // compiler name and path

func init() {
	// determine compiler
	switch runtime.GOARCH {
	case "386":
		gcName = "8g"
	case "amd64":
		gcName = "6g"
	case "arm":
		gcName = "5g"
	default:
		gcName = "unknown-GOARCH-compiler"
		gcPath = gcName
		return
	}
	gcPath, _ = exec.LookPath(gcName)
}

func compile(t *testing.T, dirname, filename string) {
	cmd, err := exec.Run(gcPath, []string{gcPath, filename}, nil, dirname, exec.DevNull, exec.Pipe, exec.MergeWithStdout)
	if err != nil {
		t.Errorf("%s %s failed: %s", gcName, filename, err)
		return
	}
	defer cmd.Close()

	msg, err := cmd.Wait(0)
	if err != nil {
		t.Errorf("%s %s failed: %s", gcName, filename, err)
		return
	}

	if !msg.Exited() || msg.ExitStatus() != 0 {
		t.Errorf("%s %s failed: exit status = %d", gcName, filename, msg.ExitStatus())
		output, _ := ioutil.ReadAll(cmd.Stdout)
		t.Log(string(output))
	}
}

func testPath(t *testing.T, path string) bool {
	_, _, err := GcImporter(path)
	if err != nil {
		t.Errorf("testPath(%s): %s", path, err)
		return false
	}
	return true
}

const maxTime = 3e9 // maximum allotted testing time in ns

func testDir(t *testing.T, dir string, endTime int64) (nimports int) {
	dirname := filepath.Join(pkgRoot, dir)
	list, err := ioutil.ReadDir(dirname)
	if err != nil {
		t.Errorf("testDir(%s): %s", dirname, err)
	}
	for _, f := range list {
		if time.Nanoseconds() >= endTime {
			t.Log("testing time used up")
			return
		}
		switch {
		case f.IsRegular():
			// try extensions
			for _, ext := range pkgExts {
				if strings.HasSuffix(f.Name, ext) {
					name := f.Name[0 : len(f.Name)-len(ext)] // remove extension
					if testPath(t, filepath.Join(dir, name)) {
						nimports++
					}
				}
			}
		case f.IsDirectory():
			nimports += testDir(t, filepath.Join(dir, f.Name), endTime)
		}
	}
	return
}

func TestGcImport(t *testing.T) {
	compile(t, "testdata", "exports.go")

	nimports := 0
	if testPath(t, "./testdata/exports") {
		nimports++
	}
	nimports += testDir(t, "", time.Nanoseconds()+maxTime) // installed packages
	t.Logf("tested %d imports", nimports)
}
<|endoftext|>


<commit_before>package equidistant

import (
	"github.com/ready-steady/adapt/internal"
)

func compose(levels []uint64, orders []uint64) []uint64 {
	indices := make([]uint64, len(levels))

	for i := range levels {
		indices[i] = uint64(levels[i]) | uint64(orders[i])<<internal.LEVEL_SIZE
	}

	return indices
}
<commit_msg>internal: check in missing pieces<commit_after>package internal

// Compose encodes levels and orders.
func Compose(levels []uint64, orders []uint64) (indices []uint64) {
	indices = make([]uint64, len(levels))
	for i := range levels {
		indices[i] = uint64(levels[i]) | uint64(orders[i])<<LEVEL_SIZE
	}
	return
}

// Decompose decodes levels and orders.
func Decompose(indices []uint64) (levels []uint64, orders []uint64) {
	levels, orders = make([]uint64, len(indices)), make([]uint64, len(indices))
	for i := range indices {
		levels[i], orders[i] = LEVEL_MASK&indices[i], indices[i]>>LEVEL_SIZE
	}
	return
}
<|endoftext|>


<commit_before>// Copyright 2011 Google Inc. All Rights Reserved.
// This file is available under the Apache license.

// +build gofuzz

package vm

import (
	"bytes"
	"flag"
)

func Fuzz(data []byte) int {
	flag.Set("logtostderr", "true")
	flag.Set("v", "2")
	flag.Parse()
	if _, err := Compile("fuzz", bytes.NewReader(data), true, true, false, nil); err != nil {
		return 0
	}
	return 1
}
<commit_msg>Remove flags from fuzz target.<commit_after>// Copyright 2011 Google Inc. All Rights Reserved.
// This file is available under the Apache license.

// +build gofuzz

package vm

import (
	"bytes"
)

func Fuzz(data []byte) int {
	if _, err := Compile("fuzz", bytes.NewReader(data), true, true, false, nil); err != nil {
		return 0
	}
	return 1
}
<|endoftext|>


<commit_before>// Copyright 2015 PingCAP, Inc.
//
// 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,
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"database/sql"
	"flag"
	"fmt"
	"io"
	"os"
	"runtime"
	"strings"
	"time"

	"github.com/juju/errors"
	"github.com/ngaut/log"
	"github.com/peterh/liner"
	"github.com/pingcap/tidb"
	"github.com/pingcap/tidb/util/errors2"
	"github.com/pingcap/tidb/util/printer"
)

var (
	logLevel = flag.String("L", "error", "log level")
	store    = flag.String("store", "goleveldb", "the name for the registered storage, e.g. memory, goleveldb, boltdb")
	dbPath   = flag.String("dbpath", "test/test", "db path")

	line        *liner.State
	historyPath = "/tmp/tidb_interpreter"
)

func openHistory() {
	if f, err := os.Open(historyPath); err == nil {
		line.ReadHistory(f)
		f.Close()
	}
}

func saveHistory() {
	if f, err := os.Create(historyPath); err == nil {
		line.WriteHistory(f)
		f.Close()
	}
}

func executeLine(tx *sql.Tx, txnLine string) error {
	start := time.Now()
	if tidb.IsQuery(txnLine) {
		rows, err := tx.Query(txnLine)
		elapsed := time.Since(start).Seconds()
		if err != nil {
			return errors.Trace(err)
		}
		defer rows.Close()
		cols, err := rows.Columns()
		if err != nil {
			return errors.Trace(err)
		}

		values := make([][]byte, len(cols))
		scanArgs := make([]interface{}, len(values))
		for i := range values {
			scanArgs[i] = &values[i]
		}

		var datas [][]string
		for rows.Next() {
			err := rows.Scan(scanArgs...)
			if err != nil {
				return errors.Trace(err)
			}

			data := make([]string, len(cols))
			for i, value := range values {
				if value == nil {
					data[i] = "NULL"
				} else {
					data[i] = string(value)
				}
			}

			datas = append(datas, data)
		}

		// For `cols` and `datas[i]` always has the same length,
		// no need to check return validity.
		result, _ := printer.GetPrintResult(cols, datas)
		fmt.Printf("%s", result)

		switch len(datas) {
		case 0:
			fmt.Printf("Empty set")
		case 1:
			fmt.Printf("1 row in set")
		default:
			fmt.Printf("%v rows in set", len(datas))
		}
		fmt.Printf(" (%.2f sec)\n", elapsed)
		if err := rows.Err(); err != nil {
			return errors.Trace(err)
		}
	} else {
		// TODO: last insert id
		res, err := tx.Exec(txnLine)
		elapsed := time.Since(start).Seconds()
		if err != nil {
			return errors.Trace(err)
		}
		cnt, err := res.RowsAffected()
		if err != nil {
			return errors.Trace(err)
		}
		switch cnt {
		case 0:
			fmt.Printf("Query OK, 0 row affected")
		case 1:
			fmt.Printf("Query OK, 1 row affected")
		default:
			fmt.Printf("Query OK, %v rows affected", cnt)
		}
		fmt.Printf(" (%.2f sec)\n", elapsed)
	}
	return nil
}

func mayExit(err error, l string) bool {
	if errors2.ErrorEqual(err, liner.ErrPromptAborted) || errors2.ErrorEqual(err, io.EOF) {
		fmt.Println("\nBye")
		saveHistory()
		return true
	}
	if err != nil {
		log.Fatal(errors.ErrorStack(err))
	}
	return false
}

func readStatement(prompt string) (string, error) {
	var ret string
	for {
		l, err := line.Prompt(prompt)
		if err != nil {
			return "", err
		}
		if strings.HasSuffix(l, ";") == false {
			ret += l + "\n"
			prompt = "   -> "
			continue
		}
		return ret + l, nil
	}
}

func main() {
	printer.PrintTiDBInfo()

	flag.Parse()
	log.SetLevelByString(*logLevel)
	// support for signal notify
	runtime.GOMAXPROCS(runtime.NumCPU())

	line = liner.NewLiner()
	defer line.Close()

	line.SetCtrlCAborts(true)
	openHistory()

	mdb, err := sql.Open(tidb.DriverName, *store+"://"+*dbPath)
	if err != nil {
		log.Fatal(errors.ErrorStack(err))
	}

	for {
		l, err := readStatement("tidb> ")
		if mayExit(err, l) {
			return
		}
		line.AppendHistory(l)

		// if we're in transaction
		if strings.HasPrefix(l, "BEGIN") || strings.HasPrefix(l, "begin") {
			tx, err := mdb.Begin()
			if err != nil {
				log.Error(errors.ErrorStack(err))
				continue
			}
			for {
				txnLine, err := readStatement(">> ")
				if mayExit(err, txnLine) {
					return
				}
				line.AppendHistory(txnLine)

				if !strings.HasSuffix(txnLine, ";") {
					txnLine += ";"
				}

				if strings.HasPrefix(txnLine, "COMMIT") || strings.HasPrefix(txnLine, "commit") {
					err := tx.Commit()
					if err != nil {
						log.Error(errors.ErrorStack(err))
						tx.Rollback()
					}
					break
				}
				// normal sql statement
				err = executeLine(tx, txnLine)
				if err != nil {
					log.Error(errors.ErrorStack(err))
					tx.Rollback()
					break
				}
			}
		} else {
			tx, err := mdb.Begin()
			if err != nil {
				log.Error(errors.ErrorStack(err))
				continue
			}
			err = executeLine(tx, l)
			if err != nil {
				log.Error(errors.ErrorStack(err))
				tx.Rollback()
			} else {
				tx.Commit()
			}
		}
	}
}
<commit_msg>interpreter: merge cases<commit_after>// Copyright 2015 PingCAP, Inc.
//
// 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,
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"database/sql"
	"flag"
	"fmt"
	"io"
	"os"
	"runtime"
	"strings"
	"time"

	"github.com/juju/errors"
	"github.com/ngaut/log"
	"github.com/peterh/liner"
	"github.com/pingcap/tidb"
	"github.com/pingcap/tidb/util/errors2"
	"github.com/pingcap/tidb/util/printer"
)

var (
	logLevel = flag.String("L", "error", "log level")
	store    = flag.String("store", "goleveldb", "the name for the registered storage, e.g. memory, goleveldb, boltdb")
	dbPath   = flag.String("dbpath", "test/test", "db path")

	line        *liner.State
	historyPath = "/tmp/tidb_interpreter"
)

func openHistory() {
	if f, err := os.Open(historyPath); err == nil {
		line.ReadHistory(f)
		f.Close()
	}
}

func saveHistory() {
	if f, err := os.Create(historyPath); err == nil {
		line.WriteHistory(f)
		f.Close()
	}
}

func executeLine(tx *sql.Tx, txnLine string) error {
	start := time.Now()
	if tidb.IsQuery(txnLine) {
		rows, err := tx.Query(txnLine)
		elapsed := time.Since(start).Seconds()
		if err != nil {
			return errors.Trace(err)
		}
		defer rows.Close()
		cols, err := rows.Columns()
		if err != nil {
			return errors.Trace(err)
		}

		values := make([][]byte, len(cols))
		scanArgs := make([]interface{}, len(values))
		for i := range values {
			scanArgs[i] = &values[i]
		}

		var datas [][]string
		for rows.Next() {
			err := rows.Scan(scanArgs...)
			if err != nil {
				return errors.Trace(err)
			}

			data := make([]string, len(cols))
			for i, value := range values {
				if value == nil {
					data[i] = "NULL"
				} else {
					data[i] = string(value)
				}
			}

			datas = append(datas, data)
		}

		// For `cols` and `datas[i]` always has the same length,
		// no need to check return validity.
		result, _ := printer.GetPrintResult(cols, datas)
		fmt.Printf("%s", result)

		switch len(datas) {
		case 0:
			fmt.Printf("Empty set")
		case 1:
			fmt.Printf("1 row in set")
		default:
			fmt.Printf("%v rows in set", len(datas))
		}
		fmt.Printf(" (%.2f sec)\n", elapsed)
		if err := rows.Err(); err != nil {
			return errors.Trace(err)
		}
	} else {
		// TODO: last insert id
		res, err := tx.Exec(txnLine)
		elapsed := time.Since(start).Seconds()
		if err != nil {
			return errors.Trace(err)
		}
		cnt, err := res.RowsAffected()
		if err != nil {
			return errors.Trace(err)
		}
		switch cnt {
		case 0, 1:
			fmt.Printf("Query OK, %d row affected", cnt)
		default:
			fmt.Printf("Query OK, %d rows affected", cnt)
		}
		fmt.Printf(" (%.2f sec)\n", elapsed)
	}
	return nil
}

func mayExit(err error, l string) bool {
	if errors2.ErrorEqual(err, liner.ErrPromptAborted) || errors2.ErrorEqual(err, io.EOF) {
		fmt.Println("\nBye")
		saveHistory()
		return true
	}
	if err != nil {
		log.Fatal(errors.ErrorStack(err))
	}
	return false
}

func readStatement(prompt string) (string, error) {
	var ret string
	for {
		l, err := line.Prompt(prompt)
		if err != nil {
			return "", err
		}
		if strings.HasSuffix(l, ";") == false {
			ret += l + "\n"
			prompt = "   -> "
			continue
		}
		return ret + l, nil
	}
}

func main() {
	printer.PrintTiDBInfo()

	flag.Parse()
	log.SetLevelByString(*logLevel)
	// support for signal notify
	runtime.GOMAXPROCS(runtime.NumCPU())

	line = liner.NewLiner()
	defer line.Close()

	line.SetCtrlCAborts(true)
	openHistory()

	mdb, err := sql.Open(tidb.DriverName, *store+"://"+*dbPath)
	if err != nil {
		log.Fatal(errors.ErrorStack(err))
	}

	for {
		l, err := readStatement("tidb> ")
		if mayExit(err, l) {
			return
		}
		line.AppendHistory(l)

		// if we're in transaction
		if strings.HasPrefix(l, "BEGIN") || strings.HasPrefix(l, "begin") {
			tx, err := mdb.Begin()
			if err != nil {
				log.Error(errors.ErrorStack(err))
				continue
			}
			for {
				txnLine, err := readStatement(">> ")
				if mayExit(err, txnLine) {
					return
				}
				line.AppendHistory(txnLine)

				if !strings.HasSuffix(txnLine, ";") {
					txnLine += ";"
				}

				if strings.HasPrefix(txnLine, "COMMIT") || strings.HasPrefix(txnLine, "commit") {
					err := tx.Commit()
					if err != nil {
						log.Error(errors.ErrorStack(err))
						tx.Rollback()
					}
					break
				}
				// normal sql statement
				err = executeLine(tx, txnLine)
				if err != nil {
					log.Error(errors.ErrorStack(err))
					tx.Rollback()
					break
				}
			}
		} else {
			tx, err := mdb.Begin()
			if err != nil {
				log.Error(errors.ErrorStack(err))
				continue
			}
			err = executeLine(tx, l)
			if err != nil {
				log.Error(errors.ErrorStack(err))
				tx.Rollback()
			} else {
				tx.Commit()
			}
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	_ "go/types"

	"github.com/hyperledger/fabric/core/chaincode/shim"
)

// SimpleChaincode example simple Chaincode implementation
type SimpleChaincode struct {
}

// ##### MAIN ##### //
func main() {
	err := shim.Start(new(SimpleChaincode))
	if err != nil {
		fmt.Printf("Error starting Simple chaincode: %s", err)
	}
}

// Init is executed 1 time when the chaincode is deployed
func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {

	//return nothing for the moment
	return nil, nil
}

// Invoke is called
func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {

	//return nothing for the moment
	return nil, nil
}

// Query callback representing the query of a chaincode
func (t *SimpleChaincode) Query(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {

	//return nothing for the moment
	return nil, nil

}
<commit_msg>Chaincode version 1 finished<commit_after><|endoftext|>


<commit_before>// Copyright 2019 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 queue provides queue implementations that can be used for
// asynchronous scheduling of fetch actions.
package queue

import (
	"context"
	"crypto/sha256"
	"fmt"
	"os"
	"time"

	cloudtasks "cloud.google.com/go/cloudtasks/apiv2"
	"golang.org/x/discovery/internal/config"
	"golang.org/x/discovery/internal/log"
	"golang.org/x/discovery/internal/postgres"
	"golang.org/x/discovery/internal/proxy"
	"golang.org/x/discovery/internal/source"
	taskspb "google.golang.org/genproto/googleapis/cloud/tasks/v2"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

// A Queue provides an interface for asynchronous scheduling of fetch actions.
type Queue interface {
	ScheduleFetch(ctx context.Context, modulePath, version, suffix string) error
}

// GCP provides a Queue implementation backed by the Google Cloud Tasks
// API.
type GCP struct {
	cfg     *config.Config
	client  *cloudtasks.Client
	queueID string
}

// NewGCP returns a new Queue that can be used to enqueue tasks using the
// cloud tasks API.  The given queueID should be the name of the queue in the
// cloud tasks console.
func NewGCP(cfg *config.Config, client *cloudtasks.Client, queueID string) *GCP {
	return &GCP{
		cfg:     cfg,
		client:  client,
		queueID: queueID,
	}
}

// ScheduleFetch enqueues a task on GCP to fetch the given modulePath and
// version. It returns an error if there was an error hashing the task name, or
// an error pushing the task to GCP.
func (q *GCP) ScheduleFetch(ctx context.Context, modulePath, version, suffix string) error {
	// the new taskqueue API requires a deadline of <= 30s
	ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
	defer cancel()
	queueName := fmt.Sprintf("projects/%s/locations/%s/queues/%s", q.cfg.ProjectID, q.cfg.LocationID, q.queueID)
	u := fmt.Sprintf("/fetch/%s/@v/%s", modulePath, version)
	taskID := newTaskID(modulePath, version, time.Now())
	req := &taskspb.CreateTaskRequest{
		Parent: queueName,
		Task: &taskspb.Task{
			Name: fmt.Sprintf("%s/tasks/%s", queueName, taskID),
			MessageType: &taskspb.Task_AppEngineHttpRequest{
				AppEngineHttpRequest: &taskspb.AppEngineHttpRequest{
					HttpMethod:  taskspb.HttpMethod_POST,
					RelativeUri: u,
					AppEngineRouting: &taskspb.AppEngineRouting{
						Service: os.Getenv("GAE_SERVICE"),
					},
				},
			},
		},
	}
	// If suffix is non-empty, append it to the task name. This lets us force reprocessing
	// of tasks that would normally be de-duplicated.
	if suffix != "" {
		req.Task.Name += "-" + suffix
	}

	if _, err := q.client.CreateTask(ctx, req); err != nil {
		if status.Code(err) == codes.AlreadyExists {
			log.Infof(ctx, "ignoring duplicate task ID %s", taskID)
		} else {
			return fmt.Errorf("q.client.CreateTask(ctx, req): %v", err)
		}
	}
	return nil
}

// How often the task ID for a given module and version will change.
const taskIDChangeInterval = 3 * time.Hour

// Create a task ID for the given module path and version.
// Task IDs can contain only letters ([A-Za-z]), numbers ([0-9]), hyphens (-), or underscores (_).
// Also include a truncated time in the hash, so it changes periodically.
//
// Since we truncate the time to the nearest taskIDChangeInterval, it's still possible
// for two identical tasks to appear within that time period (for example, one at 2:59
// and the other at 3:01) -- each is part of a different taskIDChangeInterval-sized chunk
// of time. But there will never be a third identical task in that interval.
func newTaskID(modulePath, version string, now time.Time) string {
	t := now.Truncate(taskIDChangeInterval)
	return fmt.Sprintf("%x", sha256.Sum256([]byte(modulePath+"@"+version+"-"+t.String())))
}

type moduleVersion struct {
	modulePath, version string
}

// InMemory is a Queue implementation that schedules in-process fetch
// operations. Unlike the GCP task queue, it will not automatically retry tasks
// on failure.
//
// This should only be used for local development.
type InMemory struct {
	proxyClient  *proxy.Client
	sourceClient *source.Client
	db           *postgres.DB

	queue chan moduleVersion
	sem   chan struct{}
}

// NewInMemory creates a new InMemory that asynchronously fetches
// from proxyClient and stores in db. It uses workerCount parallelism to
// execute these fetches.
func NewInMemory(ctx context.Context, proxyClient *proxy.Client, sourceClient *source.Client, db *postgres.DB, workerCount int,
	processFunc func(context.Context, string, string, *proxy.Client, *source.Client, *postgres.DB) (int, error)) *InMemory {
	q := &InMemory{
		proxyClient:  proxyClient,
		sourceClient: sourceClient,
		db:           db,
		queue:        make(chan moduleVersion, 1000),
		sem:          make(chan struct{}, workerCount),
	}
	go q.process(ctx, processFunc)
	return q
}

func (q *InMemory) process(ctx context.Context, processFunc func(context.Context, string, string, *proxy.Client, *source.Client, *postgres.DB) (int, error)) {

	for v := range q.queue {
		select {
		case <-ctx.Done():
			return
		case q.sem <- struct{}{}:
		}

		// If a worker is available, make a request to the fetch service inside a
		// goroutine and wait for it to finish.
		go func(v moduleVersion) {
			defer func() { <-q.sem }()

			log.Infof(ctx, "Fetch requested: %q %q (workerCount = %d)", v.modulePath, v.version, cap(q.sem))

			fetchCtx, cancel := context.WithTimeout(ctx, 5*time.Minute)
			defer cancel()

			if _, err := processFunc(fetchCtx, v.modulePath, v.version, q.proxyClient, q.sourceClient, q.db); err != nil {
				log.Error(fetchCtx, err)
			}
		}(v)
	}
}

// ScheduleFetch pushes a fetch task into the local queue to be processed
// asynchronously.
func (q *InMemory) ScheduleFetch(ctx context.Context, modulePath, version, suffix string) error {
	q.queue <- moduleVersion{modulePath, version}
	return nil
}

// WaitForTesting waits for all queued requests to finish. It should only be
// used by test code.
func (q InMemory) WaitForTesting(ctx context.Context) {
	for i := 0; i < cap(q.sem); i++ {
		select {
		case <-ctx.Done():
			return
		case q.sem <- struct{}{}:
		}
	}
	close(q.queue)
}
<commit_msg>internal/queue: change task IDs more frequently<commit_after>// Copyright 2019 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 queue provides queue implementations that can be used for
// asynchronous scheduling of fetch actions.
package queue

import (
	"context"
	"crypto/sha256"
	"fmt"
	"os"
	"time"

	cloudtasks "cloud.google.com/go/cloudtasks/apiv2"
	"golang.org/x/discovery/internal/config"
	"golang.org/x/discovery/internal/log"
	"golang.org/x/discovery/internal/postgres"
	"golang.org/x/discovery/internal/proxy"
	"golang.org/x/discovery/internal/source"
	taskspb "google.golang.org/genproto/googleapis/cloud/tasks/v2"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

// A Queue provides an interface for asynchronous scheduling of fetch actions.
type Queue interface {
	ScheduleFetch(ctx context.Context, modulePath, version, suffix string) error
}

// GCP provides a Queue implementation backed by the Google Cloud Tasks
// API.
type GCP struct {
	cfg     *config.Config
	client  *cloudtasks.Client
	queueID string
}

// NewGCP returns a new Queue that can be used to enqueue tasks using the
// cloud tasks API.  The given queueID should be the name of the queue in the
// cloud tasks console.
func NewGCP(cfg *config.Config, client *cloudtasks.Client, queueID string) *GCP {
	return &GCP{
		cfg:     cfg,
		client:  client,
		queueID: queueID,
	}
}

// ScheduleFetch enqueues a task on GCP to fetch the given modulePath and
// version. It returns an error if there was an error hashing the task name, or
// an error pushing the task to GCP.
func (q *GCP) ScheduleFetch(ctx context.Context, modulePath, version, suffix string) error {
	// the new taskqueue API requires a deadline of <= 30s
	ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
	defer cancel()
	queueName := fmt.Sprintf("projects/%s/locations/%s/queues/%s", q.cfg.ProjectID, q.cfg.LocationID, q.queueID)
	u := fmt.Sprintf("/fetch/%s/@v/%s", modulePath, version)
	taskID := newTaskID(modulePath, version, time.Now())
	req := &taskspb.CreateTaskRequest{
		Parent: queueName,
		Task: &taskspb.Task{
			Name: fmt.Sprintf("%s/tasks/%s", queueName, taskID),
			MessageType: &taskspb.Task_AppEngineHttpRequest{
				AppEngineHttpRequest: &taskspb.AppEngineHttpRequest{
					HttpMethod:  taskspb.HttpMethod_POST,
					RelativeUri: u,
					AppEngineRouting: &taskspb.AppEngineRouting{
						Service: os.Getenv("GAE_SERVICE"),
					},
				},
			},
		},
	}
	// If suffix is non-empty, append it to the task name. This lets us force reprocessing
	// of tasks that would normally be de-duplicated.
	if suffix != "" {
		req.Task.Name += "-" + suffix
	}

	if _, err := q.client.CreateTask(ctx, req); err != nil {
		if status.Code(err) == codes.AlreadyExists {
			log.Infof(ctx, "ignoring duplicate task ID %s", taskID)
		} else {
			return fmt.Errorf("q.client.CreateTask(ctx, req): %v", err)
		}
	}
	return nil
}

// How often the task ID for a given module and version will change.
const taskIDChangeInterval = time.Hour

// Create a task ID for the given module path and version.
// Task IDs can contain only letters ([A-Za-z]), numbers ([0-9]), hyphens (-), or underscores (_).
// Also include a truncated time in the hash, so it changes periodically.
//
// Since we truncate the time to the nearest taskIDChangeInterval, it's still possible
// for two identical tasks to appear within that time period (for example, one at 2:59
// and the other at 3:01) -- each is part of a different taskIDChangeInterval-sized chunk
// of time. But there will never be a third identical task in that interval.
func newTaskID(modulePath, version string, now time.Time) string {
	t := now.Truncate(taskIDChangeInterval)
	return fmt.Sprintf("%x", sha256.Sum256([]byte(modulePath+"@"+version+"-"+t.String())))
}

type moduleVersion struct {
	modulePath, version string
}

// InMemory is a Queue implementation that schedules in-process fetch
// operations. Unlike the GCP task queue, it will not automatically retry tasks
// on failure.
//
// This should only be used for local development.
type InMemory struct {
	proxyClient  *proxy.Client
	sourceClient *source.Client
	db           *postgres.DB

	queue chan moduleVersion
	sem   chan struct{}
}

// NewInMemory creates a new InMemory that asynchronously fetches
// from proxyClient and stores in db. It uses workerCount parallelism to
// execute these fetches.
func NewInMemory(ctx context.Context, proxyClient *proxy.Client, sourceClient *source.Client, db *postgres.DB, workerCount int,
	processFunc func(context.Context, string, string, *proxy.Client, *source.Client, *postgres.DB) (int, error)) *InMemory {
	q := &InMemory{
		proxyClient:  proxyClient,
		sourceClient: sourceClient,
		db:           db,
		queue:        make(chan moduleVersion, 1000),
		sem:          make(chan struct{}, workerCount),
	}
	go q.process(ctx, processFunc)
	return q
}

func (q *InMemory) process(ctx context.Context, processFunc func(context.Context, string, string, *proxy.Client, *source.Client, *postgres.DB) (int, error)) {

	for v := range q.queue {
		select {
		case <-ctx.Done():
			return
		case q.sem <- struct{}{}:
		}

		// If a worker is available, make a request to the fetch service inside a
		// goroutine and wait for it to finish.
		go func(v moduleVersion) {
			defer func() { <-q.sem }()

			log.Infof(ctx, "Fetch requested: %q %q (workerCount = %d)", v.modulePath, v.version, cap(q.sem))

			fetchCtx, cancel := context.WithTimeout(ctx, 5*time.Minute)
			defer cancel()

			if _, err := processFunc(fetchCtx, v.modulePath, v.version, q.proxyClient, q.sourceClient, q.db); err != nil {
				log.Error(fetchCtx, err)
			}
		}(v)
	}
}

// ScheduleFetch pushes a fetch task into the local queue to be processed
// asynchronously.
func (q *InMemory) ScheduleFetch(ctx context.Context, modulePath, version, suffix string) error {
	q.queue <- moduleVersion{modulePath, version}
	return nil
}

// WaitForTesting waits for all queued requests to finish. It should only be
// used by test code.
func (q InMemory) WaitForTesting(ctx context.Context) {
	for i := 0; i < cap(q.sem); i++ {
		select {
		case <-ctx.Done():
			return
		case q.sem <- struct{}{}:
		}
	}
	close(q.queue)
}
<|endoftext|>


<commit_before>// Copyright 2011 Google Inc. All Rights Reserved.
// This file is available under the Apache license.

// Package tailer provides a class that is responsible for tailing log files
// and extracting new log lines to be passed into the virtual machines.
package tailer

// For regular files, mtail gets notified on modifications (i.e. appends) to
// log files that are being watched, in order to read the new lines. Log files
// can also be rotated, so mtail is also notified of creates in the log file
// directory.

import (
	"expvar"
	"html/template"
	"io"
	"os"
	"path/filepath"
	"sync"
	"time"

	"github.com/golang/glog"
	"github.com/pkg/errors"

	"github.com/google/mtail/internal/logline"
	"github.com/google/mtail/internal/watcher"
)

var (
	// logCount records the number of logs that are being tailed
	logCount = expvar.NewInt("log_count")
)

// Tailer receives notification of changes from a Watcher and extracts new log
// lines from files. It also handles new log file creation events and log
// rotations.
type Tailer struct {
	lines chan<- *logline.LogLine // Logfile lines being emitted.
	w     watcher.Watcher

	handlesMu sync.RWMutex     // protects `handles'
	handles   map[string]*File // File handles for each pathname.

	globPatternsMu sync.RWMutex        // protects `globPatterns'
	globPatterns   map[string]struct{} // glob patterns to match newly created files in dir paths against

	runDone chan struct{} // Signals termination of the run goroutine.

	eventsHandle int // record the handle with which to add new log files to the watcher

	oneShot bool
}

// OneShot puts the tailer in one-shot mode.
func OneShot(t *Tailer) error {
	t.oneShot = true
	return nil
}

// New creates a new Tailer.
func New(lines chan<- *logline.LogLine, w watcher.Watcher, options ...func(*Tailer) error) (*Tailer, error) {
	if lines == nil {
		return nil, errors.New("can't create tailer without lines channel")
	}
	if w == nil {
		return nil, errors.New("can't create tailer without W")
	}
	t := &Tailer{
		lines:        lines,
		w:            w,
		handles:      make(map[string]*File),
		globPatterns: make(map[string]struct{}),
		runDone:      make(chan struct{}),
	}
	if err := t.SetOption(options...); err != nil {
		return nil, err
	}
	handle, eventsChan := t.w.Events()
	t.eventsHandle = handle
	go t.run(eventsChan)
	return t, nil
}

// SetOption takes one or more option functions and applies them in order to Tailer.
func (t *Tailer) SetOption(options ...func(*Tailer) error) error {
	for _, option := range options {
		if err := option(t); err != nil {
			return err
		}
	}
	return nil
}

// setHandle sets a file handle under it's pathname
func (t *Tailer) setHandle(pathname string, f *File) error {
	absPath, err := filepath.Abs(pathname)
	if err != nil {
		return errors.Wrapf(err, "Failed to lookup abspath of %q", pathname)
	}
	t.handlesMu.Lock()
	defer t.handlesMu.Unlock()
	t.handles[absPath] = f
	return nil
}

// handleForPath retrives a file handle for a pathname.
func (t *Tailer) handleForPath(pathname string) (*File, bool) {
	absPath, err := filepath.Abs(pathname)
	if err != nil {
		glog.V(2).Infof("Couldn't resolve path %q: %s", pathname, err)
		return nil, false
	}
	t.handlesMu.Lock()
	defer t.handlesMu.Unlock()
	fd, ok := t.handles[absPath]
	return fd, ok
}

func (t *Tailer) hasHandle(pathname string) bool {
	_, ok := t.handleForPath(pathname)
	return ok
}

// AddPattern adds a pattern to the list of patterns to filter filenames against.
func (t *Tailer) AddPattern(pattern string) error {
	absPath, err := filepath.Abs(pattern)
	if err != nil {
		glog.V(2).Infof("Couldn't canonicalize path %q: %s", pattern, err)
		return err
	}
	glog.V(2).Infof("AddPattern: %s", absPath)
	t.globPatternsMu.Lock()
	t.globPatterns[absPath] = struct{}{}
	t.globPatternsMu.Unlock()
	return nil
}

// TailPattern registers a pattern to be tailed.  If pattern is a plain
// file then it is watched for updates and opened.  If pattern is a glob, then
// all paths that match the glob are opened and watched, and the directories
// containing those matches, if any, are watched.
func (t *Tailer) TailPattern(pattern string) error {
	if err := t.AddPattern(pattern); err != nil {
		return err
	}
	// Add a watch on the containing directory, so we know when a rotation
	// occurs or something shows up that matches this pattern.
	if err := t.watchDirname(pattern); err != nil {
		return err
	}
	matches, err := filepath.Glob(pattern)
	if err != nil {
		return err
	}
	glog.V(1).Infof("glob matches: %v", matches)
	// Error if there are no matches, but if they show up later, they'll get picked up by the directory watch set above.
	if len(matches) == 0 {
		return errors.Errorf("No matches for pattern %q", pattern)
	}
	for _, pathname := range matches {
		err := t.TailPath(pathname)
		if err != nil {
			return errors.Wrapf(err, "attempting to tail %q", pathname)
		}
	}
	return nil
}

// TailPath registers a filesystem pathname to be tailed.
func (t *Tailer) TailPath(pathname string) error {
	if t.hasHandle(pathname) {
		glog.V(2).Infof("already watching %q", pathname)
		return nil
	}
	if err := t.w.Add(pathname, t.eventsHandle); err != nil {
		return err
	}
	// New file at start of program, seek to EOF.
	return t.openLogPath(pathname, false)
}

// handleLogEvent is dispatched when an Event is received, causing the tailer
// to read all available bytes from an already-opened file and send each log
// line onto lines channel.  Because we handle rotations and truncates when
// reaching EOF in the file reader itself, we don't care what the signal is
// from the filewatcher.
func (t *Tailer) handleLogEvent(pathname string) {
	glog.V(2).Infof("handleLogUpdate %s", pathname)
	fd, ok := t.handleForPath(pathname)
	if !ok {
		glog.V(1).Infof("No file handle found for %q, but is being watched", pathname)
		// We want to open files we have watches on in case the file was
		// unreadable before now; but we have to copmare against the glob to be
		// sure we don't just add all the files in a watched directory as they
		// get modified.
		t.handleCreateGlob(pathname)
		return
	}
	doFollow(fd)
}

// doFollow performs the Follow on an existing file descriptor, logging any errors
func doFollow(fd *File) {
	err := fd.Follow()
	if err != nil && err != io.EOF {
		glog.Info(err)
	}
}

// pollHandles walks the handles map and polls them all in series.
func (t *Tailer) pollHandles() {
	t.handlesMu.RLock()
	defer t.handlesMu.RUnlock()
	for _, fd := range t.handles {
		doFollow(fd)
	}
}

// watchDirname adds the directory containing a path to be watched.
func (t *Tailer) watchDirname(pathname string) error {
	absPath, err := filepath.Abs(pathname)
	if err != nil {
		return err
	}
	d := filepath.Dir(absPath)
	return t.w.Add(d, t.eventsHandle)
}

// openLogPath opens a log file named by pathname.
func (t *Tailer) openLogPath(pathname string, seekToStart bool) error {
	glog.V(2).Infof("openlogPath %s %v", pathname, seekToStart)
	if err := t.watchDirname(pathname); err != nil {
		return err
	}
	f, err := NewFile(pathname, t.lines, seekToStart || t.oneShot)
	if err != nil {
		// Doesn't exist yet. We're watching the directory, so we'll pick it up
		// again on create; return successfully.
		if os.IsNotExist(err) {
			glog.V(1).Infof("pathname %q doesn't exist (yet?)", f.Pathname)
			return nil
		}
		return err
	}
	glog.V(2).Infof("Adding a file watch on %q", f.Pathname)
	if err := t.w.Add(f.Pathname, t.eventsHandle); err != nil {
		return err
	}
	if err := t.setHandle(pathname, f); err != nil {
		return err
	}
	if err := f.Read(); err != nil && err != io.EOF {
		return err
	}
	glog.Infof("Tailing %s", f.Pathname)
	logCount.Add(1)
	return nil
}

// handleCreateGlob matches the pathname against the glob patterns and starts tailing the file.
func (t *Tailer) handleCreateGlob(pathname string) {
	t.globPatternsMu.RLock()
	defer t.globPatternsMu.RUnlock()

	for pattern := range t.globPatterns {
		matched, err := filepath.Match(pattern, pathname)
		if err != nil {
			glog.Warningf("Unexpected bad pattern %q not detected earlier", pattern)
			continue
		}
		if !matched {
			glog.V(2).Infof("%q did not match pattern %q", pathname, pattern)
			continue
		}
		glog.V(1).Infof("New file %q matched existing glob %q", pathname, pattern)
		// If this file was just created, read from the start of the file.
		if err := t.openLogPath(pathname, true); err != nil {
			glog.Infof("Failed to tail new file %q: %s", pathname, err)
		}
		glog.V(2).Infof("started tailing %q", pathname)
		return
	}
	glog.V(2).Infof("did not start tailing %q", pathname)
}

// run the main event loop for the Tailer.  It receives notification of
// log file changes from the watcher channel, and dispatches the log event
// handler.
func (t *Tailer) run(events <-chan watcher.Event) {
	defer close(t.runDone)

	for e := range events {
		glog.V(2).Infof("Event type %#v", e)
		t.handleLogEvent(e.Pathname)
	}
	glog.Infof("Closing lines channel.")
	close(t.lines)
	glog.Infof("Shutting down tailer.")
}

// Close signals termination to the watcher.
func (t *Tailer) Close() error {
	if err := t.w.Close(); err != nil {
		return err
	}
	<-t.runDone
	return nil
}

const tailerTemplate = `

Log Tailer

Patterns

{{range $name, $val := $.Patterns}}

{{$name}}

{{end}}

Log files watched

pathname
errors
rotations
truncations
lines read

{{range $name, $val := $.Handles}}

{{$name}}

{{index $.Errors $name}}
{{index $.Rotations $name}}
{{index $.Truncs $name}}
{{index $.Lines $name}}

{{end}}

`

// WriteStatusHTML emits the Tailer's state in HTML format to the io.Writer w.
func (t *Tailer) WriteStatusHTML(w io.Writer) error {
	tpl, err := template.New("tailer").Parse(tailerTemplate)
	if err != nil {
		return err
	}
	t.handlesMu.RLock()
	defer t.handlesMu.RUnlock()
	t.globPatternsMu.RLock()
	defer t.globPatternsMu.RUnlock()
	data := struct {
		Handles   map[string]*File
		Patterns  map[string]struct{}
		Rotations map[string]string
		Lines     map[string]string
		Errors    map[string]string
		Truncs    map[string]string
	}{
		t.handles,
		t.globPatterns,
		make(map[string]string),
		make(map[string]string),
		make(map[string]string),
		make(map[string]string),
	}
	for _, pair := range []struct {
		v *expvar.Map
		m map[string]string
	}{
		{logErrors, data.Errors},
		{logRotations, data.Rotations},
		{logTruncs, data.Truncs},
		{lineCount, data.Lines},
	} {
		pair.v.Do(func(kv expvar.KeyValue) {
			pair.m[kv.Key] = kv.Value.String()
		})
	}
	return tpl.Execute(w, data)
}

// Gc removes file handles that have had no reads for 24h or more.
func (t *Tailer) Gc() error {
	t.handlesMu.Lock()
	defer t.handlesMu.Unlock()
	for k, v := range t.handles {
		if time.Since(v.LastRead) > (time.Hour * 24) {
			if err := v.Close(); err != nil {
				glog.Info(err)
			}
			delete(t.handles, k)
		}
	}
	return nil
}

// StartExpiryLoop runs a permanent goroutine to expire metrics every duration.
func (t *Tailer) StartGcLoop(duration time.Duration) {
	if duration <= 0 {
		glog.Info("Log handle expiration disabled")
		return
	}
	go func() {
		glog.Infof("Starting log handle expiry loop every %s", duration.String())
		ticker := time.NewTicker(duration)
		for {
			select {
			case <-ticker.C:
				if err := t.Gc(); err != nil {
					glog.Info(err)
				}
			}
		}
	}()
}
<commit_msg>Remove the pathname from the watcher.<commit_after>// Copyright 2011 Google Inc. All Rights Reserved.
// This file is available under the Apache license.

// Package tailer provides a class that is responsible for tailing log files
// and extracting new log lines to be passed into the virtual machines.
package tailer

// For regular files, mtail gets notified on modifications (i.e. appends) to
// log files that are being watched, in order to read the new lines. Log files
// can also be rotated, so mtail is also notified of creates in the log file
// directory.

import (
	"expvar"
	"html/template"
	"io"
	"os"
	"path/filepath"
	"sync"
	"time"

	"github.com/golang/glog"
	"github.com/pkg/errors"

	"github.com/google/mtail/internal/logline"
	"github.com/google/mtail/internal/watcher"
)

var (
	// logCount records the number of logs that are being tailed
	logCount = expvar.NewInt("log_count")
)

// Tailer receives notification of changes from a Watcher and extracts new log
// lines from files. It also handles new log file creation events and log
// rotations.
type Tailer struct {
	lines chan<- *logline.LogLine // Logfile lines being emitted.
	w     watcher.Watcher

	handlesMu sync.RWMutex     // protects `handles'
	handles   map[string]*File // File handles for each pathname.

	globPatternsMu sync.RWMutex        // protects `globPatterns'
	globPatterns   map[string]struct{} // glob patterns to match newly created files in dir paths against

	runDone chan struct{} // Signals termination of the run goroutine.

	eventsHandle int // record the handle with which to add new log files to the watcher

	oneShot bool
}

// OneShot puts the tailer in one-shot mode.
func OneShot(t *Tailer) error {
	t.oneShot = true
	return nil
}

// New creates a new Tailer.
func New(lines chan<- *logline.LogLine, w watcher.Watcher, options ...func(*Tailer) error) (*Tailer, error) {
	if lines == nil {
		return nil, errors.New("can't create tailer without lines channel")
	}
	if w == nil {
		return nil, errors.New("can't create tailer without W")
	}
	t := &Tailer{
		lines:        lines,
		w:            w,
		handles:      make(map[string]*File),
		globPatterns: make(map[string]struct{}),
		runDone:      make(chan struct{}),
	}
	if err := t.SetOption(options...); err != nil {
		return nil, err
	}
	handle, eventsChan := t.w.Events()
	t.eventsHandle = handle
	go t.run(eventsChan)
	return t, nil
}

// SetOption takes one or more option functions and applies them in order to Tailer.
func (t *Tailer) SetOption(options ...func(*Tailer) error) error {
	for _, option := range options {
		if err := option(t); err != nil {
			return err
		}
	}
	return nil
}

// setHandle sets a file handle under it's pathname
func (t *Tailer) setHandle(pathname string, f *File) error {
	absPath, err := filepath.Abs(pathname)
	if err != nil {
		return errors.Wrapf(err, "Failed to lookup abspath of %q", pathname)
	}
	t.handlesMu.Lock()
	defer t.handlesMu.Unlock()
	t.handles[absPath] = f
	return nil
}

// handleForPath retrives a file handle for a pathname.
func (t *Tailer) handleForPath(pathname string) (*File, bool) {
	absPath, err := filepath.Abs(pathname)
	if err != nil {
		glog.V(2).Infof("Couldn't resolve path %q: %s", pathname, err)
		return nil, false
	}
	t.handlesMu.Lock()
	defer t.handlesMu.Unlock()
	fd, ok := t.handles[absPath]
	return fd, ok
}

func (t *Tailer) hasHandle(pathname string) bool {
	_, ok := t.handleForPath(pathname)
	return ok
}

// AddPattern adds a pattern to the list of patterns to filter filenames against.
func (t *Tailer) AddPattern(pattern string) error {
	absPath, err := filepath.Abs(pattern)
	if err != nil {
		glog.V(2).Infof("Couldn't canonicalize path %q: %s", pattern, err)
		return err
	}
	glog.V(2).Infof("AddPattern: %s", absPath)
	t.globPatternsMu.Lock()
	t.globPatterns[absPath] = struct{}{}
	t.globPatternsMu.Unlock()
	return nil
}

// TailPattern registers a pattern to be tailed.  If pattern is a plain
// file then it is watched for updates and opened.  If pattern is a glob, then
// all paths that match the glob are opened and watched, and the directories
// containing those matches, if any, are watched.
func (t *Tailer) TailPattern(pattern string) error {
	if err := t.AddPattern(pattern); err != nil {
		return err
	}
	// Add a watch on the containing directory, so we know when a rotation
	// occurs or something shows up that matches this pattern.
	if err := t.watchDirname(pattern); err != nil {
		return err
	}
	matches, err := filepath.Glob(pattern)
	if err != nil {
		return err
	}
	glog.V(1).Infof("glob matches: %v", matches)
	// Error if there are no matches, but if they show up later, they'll get picked up by the directory watch set above.
	if len(matches) == 0 {
		return errors.Errorf("No matches for pattern %q", pattern)
	}
	for _, pathname := range matches {
		err := t.TailPath(pathname)
		if err != nil {
			return errors.Wrapf(err, "attempting to tail %q", pathname)
		}
	}
	return nil
}

// TailPath registers a filesystem pathname to be tailed.
func (t *Tailer) TailPath(pathname string) error {
	if t.hasHandle(pathname) {
		glog.V(2).Infof("already watching %q", pathname)
		return nil
	}
	if err := t.w.Add(pathname, t.eventsHandle); err != nil {
		return err
	}
	// New file at start of program, seek to EOF.
	return t.openLogPath(pathname, false)
}

// handleLogEvent is dispatched when an Event is received, causing the tailer
// to read all available bytes from an already-opened file and send each log
// line onto lines channel.  Because we handle rotations and truncates when
// reaching EOF in the file reader itself, we don't care what the signal is
// from the filewatcher.
func (t *Tailer) handleLogEvent(pathname string) {
	glog.V(2).Infof("handleLogUpdate %s", pathname)
	fd, ok := t.handleForPath(pathname)
	if !ok {
		glog.V(1).Infof("No file handle found for %q, but is being watched", pathname)
		// We want to open files we have watches on in case the file was
		// unreadable before now; but we have to copmare against the glob to be
		// sure we don't just add all the files in a watched directory as they
		// get modified.
		t.handleCreateGlob(pathname)
		return
	}
	doFollow(fd)
}

// doFollow performs the Follow on an existing file descriptor, logging any errors
func doFollow(fd *File) {
	err := fd.Follow()
	if err != nil && err != io.EOF {
		glog.Info(err)
	}
}

// pollHandles walks the handles map and polls them all in series.
func (t *Tailer) pollHandles() {
	t.handlesMu.RLock()
	defer t.handlesMu.RUnlock()
	for _, fd := range t.handles {
		doFollow(fd)
	}
}

// watchDirname adds the directory containing a path to be watched.
func (t *Tailer) watchDirname(pathname string) error {
	absPath, err := filepath.Abs(pathname)
	if err != nil {
		return err
	}
	d := filepath.Dir(absPath)
	return t.w.Add(d, t.eventsHandle)
}

// openLogPath opens a log file named by pathname.
func (t *Tailer) openLogPath(pathname string, seekToStart bool) error {
	glog.V(2).Infof("openlogPath %s %v", pathname, seekToStart)
	if err := t.watchDirname(pathname); err != nil {
		return err
	}
	f, err := NewFile(pathname, t.lines, seekToStart || t.oneShot)
	if err != nil {
		// Doesn't exist yet. We're watching the directory, so we'll pick it up
		// again on create; return successfully.
		if os.IsNotExist(err) {
			glog.V(1).Infof("pathname %q doesn't exist (yet?)", f.Pathname)
			return nil
		}
		return err
	}
	glog.V(2).Infof("Adding a file watch on %q", f.Pathname)
	if err := t.w.Add(f.Pathname, t.eventsHandle); err != nil {
		return err
	}
	if err := t.setHandle(pathname, f); err != nil {
		return err
	}
	if err := f.Read(); err != nil && err != io.EOF {
		return err
	}
	glog.Infof("Tailing %s", f.Pathname)
	logCount.Add(1)
	return nil
}

// handleCreateGlob matches the pathname against the glob patterns and starts tailing the file.
func (t *Tailer) handleCreateGlob(pathname string) {
	t.globPatternsMu.RLock()
	defer t.globPatternsMu.RUnlock()

	for pattern := range t.globPatterns {
		matched, err := filepath.Match(pattern, pathname)
		if err != nil {
			glog.Warningf("Unexpected bad pattern %q not detected earlier", pattern)
			continue
		}
		if !matched {
			glog.V(2).Infof("%q did not match pattern %q", pathname, pattern)
			continue
		}
		glog.V(1).Infof("New file %q matched existing glob %q", pathname, pattern)
		// If this file was just created, read from the start of the file.
		if err := t.openLogPath(pathname, true); err != nil {
			glog.Infof("Failed to tail new file %q: %s", pathname, err)
		}
		glog.V(2).Infof("started tailing %q", pathname)
		return
	}
	glog.V(2).Infof("did not start tailing %q", pathname)
}

// run the main event loop for the Tailer.  It receives notification of
// log file changes from the watcher channel, and dispatches the log event
// handler.
func (t *Tailer) run(events <-chan watcher.Event) {
	defer close(t.runDone)

	for e := range events {
		glog.V(2).Infof("Event type %#v", e)
		t.handleLogEvent(e.Pathname)
	}
	glog.Infof("Closing lines channel.")
	close(t.lines)
	glog.Infof("Shutting down tailer.")
}

// Close signals termination to the watcher.
func (t *Tailer) Close() error {
	if err := t.w.Close(); err != nil {
		return err
	}
	<-t.runDone
	return nil
}

const tailerTemplate = `

Log Tailer

Patterns

{{range $name, $val := $.Patterns}}

{{$name}}

{{end}}

Log files watched

pathname
errors
rotations
truncations
lines read

{{range $name, $val := $.Handles}}

{{$name}}

{{index $.Errors $name}}
{{index $.Rotations $name}}
{{index $.Truncs $name}}
{{index $.Lines $name}}

{{end}}

`

// WriteStatusHTML emits the Tailer's state in HTML format to the io.Writer w.
func (t *Tailer) WriteStatusHTML(w io.Writer) error {
	tpl, err := template.New("tailer").Parse(tailerTemplate)
	if err != nil {
		return err
	}
	t.handlesMu.RLock()
	defer t.handlesMu.RUnlock()
	t.globPatternsMu.RLock()
	defer t.globPatternsMu.RUnlock()
	data := struct {
		Handles   map[string]*File
		Patterns  map[string]struct{}
		Rotations map[string]string
		Lines     map[string]string
		Errors    map[string]string
		Truncs    map[string]string
	}{
		t.handles,
		t.globPatterns,
		make(map[string]string),
		make(map[string]string),
		make(map[string]string),
		make(map[string]string),
	}
	for _, pair := range []struct {
		v *expvar.Map
		m map[string]string
	}{
		{logErrors, data.Errors},
		{logRotations, data.Rotations},
		{logTruncs, data.Truncs},
		{lineCount, data.Lines},
	} {
		pair.v.Do(func(kv expvar.KeyValue) {
			pair.m[kv.Key] = kv.Value.String()
		})
	}
	return tpl.Execute(w, data)
}

// Gc removes file handles that have had no reads for 24h or more.
func (t *Tailer) Gc() error {
	t.handlesMu.Lock()
	defer t.handlesMu.Unlock()
	for k, v := range t.handles {
		if time.Since(v.LastRead) > (time.Hour * 24) {
			if err := t.w.Remove(v.Pathname); err != nil {
				glog.Info(err)
			}
			if err := v.Close(); err != nil {
				glog.Info(err)
			}
			delete(t.handles, k)
		}
	}
	return nil
}

// StartExpiryLoop runs a permanent goroutine to expire metrics every duration.
func (t *Tailer) StartGcLoop(duration time.Duration) {
	if duration <= 0 {
		glog.Info("Log handle expiration disabled")
		return
	}
	go func() {
		glog.Infof("Starting log handle expiry loop every %s", duration.String())
		ticker := time.NewTicker(duration)
		for {
			select {
			case <-ticker.C:
				if err := t.Gc(); err != nil {
					glog.Info(err)
				}
			}
		}
	}()
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"reflect"
	"strings"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/cloudfoundry-community/go-cfenv"
)

const (
	key   = "test-key"
	value = "test-value"
)

var creds map[string]interface{}

func main() {
	env, _ := cfenv.Current()
	services, _ := env.Services.WithLabel(os.Getenv("SERVICE_NAME"))
	if len(services) != 1 {
		log.Fatalf("Expected one service instance; got %d", len(services))
	}
	creds = services[0].Credentials

	http.HandleFunc("/", handler)
	http.ListenAndServe(":"+os.Getenv("PORT"), nil)
}

func handler(w http.ResponseWriter, r *http.Request) {
	config := &aws.Config{
		Region: aws.String(creds["region"].(string)),
		Credentials: credentials.NewStaticCredentials(
			creds["access_key_id"].(string),
			creds["secret_access_key"].(string),
			"",
		),
	}

	sess, err := session.NewSession(config)
	if err != nil {
		log.Println(err.Error())
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	svc := s3.New(sess)

	bucket := creds["bucket"].(string)
	additionalBuckets := []string{}
	for _, additionalBucket := range creds["additional_buckets"].([]interface{}) {
		additionalBuckets = append(additionalBuckets, additionalBucket.(string))
	}

	if os.Getenv("ADDITIONAL_INSTANCE_NAME") != "" {
		if len(additionalBuckets) != 1 {
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
	}

	buckets := append(additionalBuckets, bucket)

	for _, bucket := range buckets {
		if err := testBucket(bucket, svc); err != nil {
			log.Println(err.Error())
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
	}

	w.WriteHeader(http.StatusOK)
}

func testBucket(bucket string, svc *s3.S3) error {
	// Test put object
	if _, err := svc.PutObject(&s3.PutObjectInput{
		Body:   strings.NewReader(value),
		Bucket: aws.String(creds["bucket"].(string)),
		Key:    aws.String(key),
	}); err != nil {
		return err
	}

	// Test get object
	result, err := svc.GetObject(&s3.GetObjectInput{
		Bucket: aws.String(creds["bucket"].(string)),
		Key:    aws.String(key),
	})
	if err != nil {
		return err
	}

	// Test object contents
	body, err := ioutil.ReadAll(result.Body)
	if err != nil {
		return err
	}
	if string(body) != value {
		return fmt.Errorf("Got value %s; expected %s", string(body), value)
	}

	// Test public access
	resp, _ := http.Get(
		fmt.Sprintf(
			"https://s3-%s.amazonaws.com/%s/%s",
			creds["region"].(string),
			creds["bucket"].(string),
			key,
		),
	)
	expectedCode := http.StatusForbidden
	if os.Getenv("IS_PUBLIC") == "true" {
		expectedCode = http.StatusOK
	}
	if resp.StatusCode != expectedCode {
		return fmt.Errorf("expected code %d; got %d", expectedCode, resp.StatusCode)
	}

	// Test delete object
	if _, err = svc.DeleteObject(&s3.DeleteObjectInput{
		Bucket: aws.String(creds["bucket"].(string)),
		Key:    aws.String(key),
	}); err != nil {
		return err
	}

	expectedEncryption := os.Getenv("ENCRYPTION")
	if expectedEncryption != "" {
		var expectedConfig s3.ServerSideEncryptionConfiguration
		if err := json.Unmarshal([]byte(expectedEncryption), &expectedConfig); err != nil {
			return err
		}
		encryptionOutput, err := svc.GetBucketEncryption(&s3.GetBucketEncryptionInput{
			Bucket: aws.String(creds["bucket"].(string)),
		})
		if err != nil {
			return err
		}
		if !reflect.DeepEqual(expectedConfig, *encryptionOutput.ServerSideEncryptionConfiguration) {
			return fmt.Errorf("expected encryption config %+v; got %+v", expectedConfig, encryptionOutput.ServerSideEncryptionConfiguration)
		}
	}

	return nil
}
<commit_msg>Leave object in bucket; service should delete in acceptance test<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"reflect"
	"strings"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/cloudfoundry-community/go-cfenv"
)

const (
	key   = "test-key"
	value = "test-value"
)

var creds map[string]interface{}

func main() {
	env, _ := cfenv.Current()
	services, _ := env.Services.WithLabel(os.Getenv("SERVICE_NAME"))
	if len(services) != 1 {
		log.Fatalf("Expected one service instance; got %d", len(services))
	}
	creds = services[0].Credentials

	http.HandleFunc("/", handler)
	http.ListenAndServe(":"+os.Getenv("PORT"), nil)
}

func handler(w http.ResponseWriter, r *http.Request) {
	config := &aws.Config{
		Region: aws.String(creds["region"].(string)),
		Credentials: credentials.NewStaticCredentials(
			creds["access_key_id"].(string),
			creds["secret_access_key"].(string),
			"",
		),
	}

	sess, err := session.NewSession(config)
	if err != nil {
		log.Println(err.Error())
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	svc := s3.New(sess)

	bucket := creds["bucket"].(string)
	additionalBuckets := []string{}
	for _, additionalBucket := range creds["additional_buckets"].([]interface{}) {
		additionalBuckets = append(additionalBuckets, additionalBucket.(string))
	}

	if os.Getenv("ADDITIONAL_INSTANCE_NAME") != "" {
		if len(additionalBuckets) != 1 {
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
	}

	buckets := append(additionalBuckets, bucket)

	for _, bucket := range buckets {
		if err := testBucket(bucket, svc); err != nil {
			log.Println(err.Error())
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
	}

	w.WriteHeader(http.StatusOK)
}

func testBucket(bucket string, svc *s3.S3) error {
	// Test put object
	if _, err := svc.PutObject(&s3.PutObjectInput{
		Body:   strings.NewReader(value),
		Bucket: aws.String(creds["bucket"].(string)),
		Key:    aws.String(key),
	}); err != nil {
		return err
	}

	// Test get object
	result, err := svc.GetObject(&s3.GetObjectInput{
		Bucket: aws.String(creds["bucket"].(string)),
		Key:    aws.String(key),
	})
	if err != nil {
		return err
	}

	// Test object contents
	body, err := ioutil.ReadAll(result.Body)
	if err != nil {
		return err
	}
	if string(body) != value {
		return fmt.Errorf("Got value %s; expected %s", string(body), value)
	}

	// Test public access
	resp, _ := http.Get(
		fmt.Sprintf(
			"https://s3-%s.amazonaws.com/%s/%s",
			creds["region"].(string),
			creds["bucket"].(string),
			key,
		),
	)
	expectedCode := http.StatusForbidden
	if os.Getenv("IS_PUBLIC") == "true" {
		expectedCode = http.StatusOK
	}
	if resp.StatusCode != expectedCode {
		return fmt.Errorf("expected code %d; got %d", expectedCode, resp.StatusCode)
	}

	// Test delete object
	if _, err = svc.DeleteObject(&s3.DeleteObjectInput{
		Bucket: aws.String(creds["bucket"].(string)),
		Key:    aws.String(key),
	}); err != nil {
		return err
	}

	// Leave object in bucket
	if _, err := svc.PutObject(&s3.PutObjectInput{
		Body:   strings.NewReader(value),
		Bucket: aws.String(creds["bucket"].(string)),
		Key:    aws.String(key),
	}); err != nil {
		return err
	}

	expectedEncryption := os.Getenv("ENCRYPTION")
	if expectedEncryption != "" {
		var expectedConfig s3.ServerSideEncryptionConfiguration
		if err := json.Unmarshal([]byte(expectedEncryption), &expectedConfig); err != nil {
			return err
		}
		encryptionOutput, err := svc.GetBucketEncryption(&s3.GetBucketEncryptionInput{
			Bucket: aws.String(creds["bucket"].(string)),
		})
		if err != nil {
			return err
		}
		if !reflect.DeepEqual(expectedConfig, *encryptionOutput.ServerSideEncryptionConfiguration) {
			return fmt.Errorf("expected encryption config %+v; got %+v", expectedConfig, encryptionOutput.ServerSideEncryptionConfiguration)
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package arpv4

import (
	"errors"
	"network/ethernet"

	"github.com/hsheth2/logs"
)

type ARP_Table struct {
	table map[string](*ethernet.Ethernet_Addr)
}

var GlobalARP_Table = func() *ARP_Table {
	x, err := NewARP_Table()
	if err != nil {
		logs.Error.Fatalln(err)
	}
	return x
}()

func NewARP_Table() (*ARP_Table, error) {
	return &ARP_Table{
		table: make(map[string](*ethernet.Ethernet_Addr)),
	}, nil
}

func (table *ARP_Table) Lookup(ip string) (*ethernet.Ethernet_Addr, error) {
	if ans, ok := table.table[ip]; ok {
		return ans, nil
	}
	return &ethernet.Ethernet_Addr{}, errors.New("ARP lookup into table failed") // TODO call probe instead
}

func (table *ARP_Table) probe(ip string) {
	// TODO implement later
}

func (table *ARP_Table) Static_Add(ip string, addr *ethernet.Ethernet_Addr) error {
	if _, ok := table.table[ip]; ok {
		return errors.New("Cannot overwrite existing entry")
	}
	table.table[ip] = addr
	return nil
}
<commit_msg>Some edits<commit_after>package arpv4

import (
	"errors"
	"network/ethernet"

	"github.com/hsheth2/logs"
)

type ARP_Table struct {
	table map[string](*ethernet.Ethernet_Addr)
}

var GlobalARP_Table = func() *ARP_Table {
	x, err := NewARP_Table()
	if err != nil {
		logs.Error.Fatalln(err)
	}
	return x
}()

func NewARP_Table() (*ARP_Table, error) {
	return &ARP_Table{
		table: make(map[string](*ethernet.Ethernet_Addr)),
	}, nil
}

func (table *ARP_Table) Lookup(ip string) (*ethernet.Ethernet_Addr, error) {
	if ans, ok := table.table[ip]; ok {
		return ans, nil
	}
	return &ethernet.Ethernet_Addr{}, errors.New("ARP lookup into table failed") // TODO call probe instead
}

func (table *ARP_Table) probe(ip string) {
	// TODO implement later
}

func (table *ARP_Table) Static_Add(ip string, addr *ethernet.Ethernet_Addr) error {
//	if _, ok := table.table[ip]; ok {
//		return errors.New("Cannot overwrite existing entry")
//	}
	table.table[ip] = addr
	return nil
}
<|endoftext|>