<commit_before>package linux_container

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/blang/semver"
	"github.com/cloudfoundry-incubator/garden"
	"github.com/cloudfoundry-incubator/garden-linux/linux_backend"
	"github.com/cloudfoundry-incubator/garden-linux/logging"
	"github.com/cloudfoundry-incubator/garden-linux/network"
	"github.com/cloudfoundry-incubator/garden-linux/network/subnets"
	"github.com/cloudfoundry-incubator/garden-linux/process_tracker"
	"github.com/cloudfoundry/gunk/command_runner"
	"github.com/pivotal-golang/lager"
)

var MissingVersion = semver.Version{}

type UndefinedPropertyError struct {
	Key string
}

func (err UndefinedPropertyError) Error() string {
	return fmt.Sprintf("property does not exist: %s", err.Key)
}

//go:generate counterfeiter -o fake_iptables_manager/fake_iptables_manager.go . IPTablesManager
type IPTablesManager interface {
	ContainerSetup(containerID, bridgeName string, ip net.IP, network *net.IPNet) error
	ContainerTeardown(containerID string) error
}

//go:generate counterfeiter -o fake_quota_manager/fake_quota_manager.go . QuotaManager
type QuotaManager interface {
	SetLimits(logger lager.Logger, containerRootFSPath string, limits garden.DiskLimits) error
	GetLimits(logger lager.Logger, containerRootFSPath string) (garden.DiskLimits, error)
	GetUsage(logger lager.Logger, containerRootFSPath string) (garden.ContainerDiskStat, error)

	Setup() error

	IsEnabled() bool
}

//go:generate counterfeiter -o fake_network_statisticser/fake_network_statisticser.go . NetworkStatisticser
type NetworkStatisticser interface {
	Statistics() (stats garden.ContainerNetworkStat, err error)
}

//go:generate counterfeiter -o fake_watcher/fake_watcher.go . Watcher
type Watcher interface {
	Watch(func()) error
	Unwatch()
}

type BandwidthManager interface {
	SetLimits(lager.Logger, garden.BandwidthLimits) error
	GetLimits(lager.Logger) (garden.ContainerBandwidthStat, error)
}

type CgroupsManager interface {
	Set(subsystem, name, value string) error
	Get(subsystem, name string) (string, error)
	SubsystemPath(subsystem string) (string, error)
}

type LinuxContainer struct {
	propertiesMutex sync.RWMutex
	stateMutex      sync.RWMutex
	eventsMutex     sync.RWMutex
	bandwidthMutex  sync.RWMutex
	diskMutex       sync.RWMutex
	memoryMutex     sync.RWMutex
	cpuMutex        sync.RWMutex
	netInsMutex     sync.RWMutex
	netOutsMutex    sync.RWMutex
	linux_backend.LinuxContainerSpec

	portPool         PortPool
	runner           command_runner.CommandRunner
	cgroupsManager   CgroupsManager
	quotaManager     QuotaManager
	bandwidthManager BandwidthManager
	processTracker   process_tracker.ProcessTracker
	filter           network.Filter
	ipTablesManager  IPTablesManager
	processIDPool    *ProcessIDPool

	graceTime time.Duration

	oomWatcher Watcher

	mtu uint32

	netStats NetworkStatisticser

	logger lager.Logger
}

type ProcessIDPool struct {
	currentProcessID uint32
	mu               sync.Mutex
}

func (p *ProcessIDPool) Next() uint32 {
	p.mu.Lock()
	defer p.mu.Unlock()

	p.currentProcessID = p.currentProcessID + 1
	return p.currentProcessID
}

func (p *ProcessIDPool) Restore(id uint32) {
	p.mu.Lock()
	defer p.mu.Unlock()

	if id >= p.currentProcessID {
		p.currentProcessID = id
	}
}

type PortPool interface {
	Acquire() (uint32, error)
	Remove(uint32) error
	Release(uint32)
}

func NewLinuxContainer(
	spec linux_backend.LinuxContainerSpec,
	portPool PortPool,
	runner command_runner.CommandRunner,
	cgroupsManager CgroupsManager,
	quotaManager QuotaManager,
	bandwidthManager BandwidthManager,
	processTracker process_tracker.ProcessTracker,
	filter network.Filter,
	ipTablesManager IPTablesManager,
	netStats NetworkStatisticser,
	oomWatcher Watcher,
	logger lager.Logger,
) *LinuxContainer {
	return &LinuxContainer{
		LinuxContainerSpec: spec,

		portPool:         portPool,
		runner:           runner,
		cgroupsManager:   cgroupsManager,
		quotaManager:     quotaManager,
		bandwidthManager: bandwidthManager,
		processTracker:   processTracker,
		filter:           filter,
		ipTablesManager:  ipTablesManager,
		processIDPool:    &ProcessIDPool{},
		netStats:         netStats,
		graceTime:        spec.GraceTime,

		oomWatcher: oomWatcher,
		logger:     logger,
	}
}

func (c *LinuxContainer) ID() string {
	return c.LinuxContainerSpec.ID
}

func (c *LinuxContainer) ResourceSpec() linux_backend.LinuxContainerSpec {
	return c.LinuxContainerSpec
}

func (c *LinuxContainer) RootFSPath() string {
	return c.ContainerRootFSPath
}

func (c *LinuxContainer) Handle() string {
	return c.LinuxContainerSpec.Handle
}

func (c *LinuxContainer) GraceTime() time.Duration {
	return c.graceTime
}

func (c *LinuxContainer) SetGraceTime(graceTime time.Duration) error {
	c.graceTime = graceTime
	return nil
}

func (c *LinuxContainer) State() linux_backend.State {
	c.stateMutex.RLock()
	defer c.stateMutex.RUnlock()

	return c.LinuxContainerSpec.State<commit_msg>Serialize access to grace time<commit_after>package linux_container

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/blang/semver"
	"github.com/cloudfoundry-incubator/garden"
	"github.com/cloudfoundry-incubator/garden-linux/linux_backend"
	"github.com/cloudfoundry-incubator/garden-linux/logging"
	"github.com/cloudfoundry-incubator/garden-linux/network"
	"github.com/cloudfoundry-incubator/garden-linux/network/subnets"
	"github.com/cloudfoundry-incubator/garden-linux/process_tracker"
	"github.com/cloudfoundry/gunk/command_runner"
	"github.com/pivotal-golang/lager"
)

var MissingVersion = semver.Version{}

type UndefinedPropertyError struct {
	Key string
}

func (err UndefinedPropertyError) Error() string {
	return fmt.Sprintf("property does not exist: %s", err.Key)
}

//go:generate counterfeiter -o fake_iptables_manager/fake_iptables_manager.go . IPTablesManager
type IPTablesManager interface {
	ContainerSetup(containerID, bridgeName string, ip net.IP, network *net.IPNet) error
	ContainerTeardown(containerID string) error
}

//go:generate counterfeiter -o fake_quota_manager/fake_quota_manager.go . QuotaManager
type QuotaManager interface {
	SetLimits(logger lager.Logger, containerRootFSPath string, limits garden.DiskLimits) error
	GetLimits(logger lager.Logger, containerRootFSPath string) (garden.DiskLimits, error)
	GetUsage(logger lager.Logger, containerRootFSPath string) (garden.ContainerDiskStat, error)

	Setup() error

	IsEnabled() bool
}

//go:generate counterfeiter -o fake_network_statisticser/fake_network_statisticser.go . NetworkStatisticser
type NetworkStatisticser interface {
	Statistics() (stats garden.ContainerNetworkStat, err error)
}

//go:generate counterfeiter -o fake_watcher/fake_watcher.go . Watcher
type Watcher interface {
	Watch(func()) error
	Unwatch()
}

type BandwidthManager interface {
	SetLimits(lager.Logger, garden.BandwidthLimits) error
	GetLimits(lager.Logger) (garden.ContainerBandwidthStat, error)
}

type CgroupsManager interface {
	Set(subsystem, name, value string) error
	Get(subsystem, name string) (string, error)
	SubsystemPath(subsystem string) (string, error)
}

type LinuxContainer struct {
	propertiesMutex sync.RWMutex
	stateMutex      sync.RWMutex
	eventsMutex     sync.RWMutex
	bandwidthMutex  sync.RWMutex
	diskMutex       sync.RWMutex
	memoryMutex     sync.RWMutex
	cpuMutex        sync.RWMutex
	netInsMutex     sync.RWMutex
	netOutsMutex    sync.RWMutex
	graceTimeMutex  sync.RWMutex
	linux_backend.LinuxContainerSpec

	portPool         PortPool
	runner           command_runner.CommandRunner
	cgroupsManager   CgroupsManager
	quotaManager     QuotaManager
	bandwidthManager BandwidthManager
	processTracker   process_tracker.ProcessTracker
	filter           network.Filter
	ipTablesManager  IPTablesManager
	processIDPool    *ProcessIDPool

	graceTime time.Duration

	oomWatcher Watcher

	mtu uint32

	netStats NetworkStatisticser

	logger lager.Logger
}

type ProcessIDPool struct {
	currentProcessID uint32
	mu               sync.Mutex
}

func (p *ProcessIDPool) Next() uint32 {
	p.mu.Lock()
	defer p.mu.Unlock()

	p.currentProcessID = p.currentProcessID + 1
	return p.currentProcessID
}

func (p *ProcessIDPool) Restore(id uint32) {
	p.mu.Lock()
	defer p.mu.Unlock()

	if id >= p.currentProcessID {
		p.currentProcessID = id
	}
}

type PortPool interface {
	Acquire() (uint32, error)
	Remove(uint32) error
	Release(uint32)
}

func NewLinuxContainer(
	spec linux_backend.LinuxContainerSpec,
	portPool PortPool,
	runner command_runner.CommandRunner,
	cgroupsManager CgroupsManager,
	quotaManager QuotaManager,
	bandwidthManager BandwidthManager,
	processTracker process_tracker.ProcessTracker,
	filter network.Filter,
	ipTablesManager IPTablesManager,
	netStats NetworkStatisticser,
	oomWatcher Watcher,
	logger lager.Logger,
) *LinuxContainer {
	return &LinuxContainer{
		LinuxContainerSpec: spec,

		portPool:         portPool,
		runner:           runner,
		cgroupsManager:   cgroupsManager,
		quotaManager:     quotaManager,
		bandwidthManager: bandwidthManager,
		processTracker:   processTracker,
		filter:           filter,
		ipTablesManager:  ipTablesManager,
		processIDPool:    &ProcessIDPool{},
		netStats:         netStats,
		graceTime:        spec.GraceTime,

		oomWatcher: oomWatcher,
		logger:     logger,
	}
}

func (c *LinuxContainer) ID() string {
	return c.LinuxContainerSpec.ID
}

func (c *LinuxContainer) ResourceSpec() linux_backend.LinuxContainerSpec {
	return c.LinuxContainerSpec
}

func (c *LinuxContainer) RootFSPath() string {
	return c.ContainerRootFSPath
}

func (c *LinuxContainer) Handle() string {
	return c.LinuxContainerSpec.Handle
}

func (c *LinuxContainer) GraceTime() time.Duration {
	c.graceTimeMutex.RLock()
	defer c.graceTimeMutex.RUnlock()
	return c.graceTime
}

func (c *LinuxContainer) SetGraceTime(graceTime time.Duration) error {
	c.graceTimeMutex.Lock()
	defer c.graceTimeMutex.Unlock()
	c.graceTime = graceTime
	return nil
}

func (c *LinuxContainer) State() linux_backend.State {
	c.stateMutex.RLock()
	defer c.stateMutex.RUnlock()

	return c.LinuxContainerSpec.State
{'fraction_non_alphanumeric': 0.08692676249144421, 'fraction_numerical': 0.002933411557641537, 'mean_word_length': 4.844571428571428, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4209096', 'n_tokens_mistral': 3460, 'n_tokens_neox': 3399, 'n_words': 709}