<commit_before>/*
Copyright 2016 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package core

import (
	"time"

	"k8s.io/autoscaler/cluster-autoscaler/clusterstate/utils"
	"k8s.io/autoscaler/cluster-autoscaler/metrics"
	"k8s.io/autoscaler/cluster-autoscaler/simulator"
	"k8s.io/autoscaler/cluster-autoscaler/utils/errors"
	kube_util "k8s.io/autoscaler/cluster-autoscaler/utils/kubernetes"
	kube_record "k8s.io/client-go/tools/record"
	kube_client "k8s.io/kubernetes/pkg/client/clientset_generated/clientset"

	"github.com/golang/glog"
	"k8s.io/autoscaler/cluster-autoscaler/cloudprovider"
)

// StaticAutoscaler is an autoscaler which has all the core functionality of a CA but without the reconfiguration feature
type StaticAutoscaler struct {
	// AutoscalingContext consists of validated settings and options for this autoscaler
	*AutoscalingContext
	kube_util.ListerRegistry
	lastScaleUpTime          time.Time
	lastScaleDownFailedTrial time.Time
	scaleDown                *ScaleDown
}

// NewStaticAutoscaler creates an instance of Autoscaler filled with provided parameters
func NewStaticAutoscaler(opts AutoscalingOptions, predicateChecker *simulator.PredicateChecker,
	kubeClient kube_client.Interface, kubeEventRecorder kube_record.EventRecorder, listerRegistry kube_util.ListerRegistry) (*StaticAutoscaler, errors.AutoscalerError) {
	logRecorder, err := utils.NewStatusMapRecorder(kubeClient, opts.ConfigNamespace, kubeEventRecorder, opts.WriteStatusConfigMap)
	if err != nil {
		glog.Error("Failed to initialize status configmap, unable to write status events")
		// Get a dummy, so we can at least safely call the methods
		// TODO(maciekpytel): recover from this after successfull status configmap update?
		logRecorder, _ = utils.NewStatusMapRecorder(kubeClient, opts.ConfigNamespace, kubeEventRecorder, false)
	}
	autoscalingContext, errctx := NewAutoscalingContext(opts, predicateChecker, kubeClient, kubeEventRecorder, logRecorder, listerRegistry)
	if errctx != nil {
		return nil, errctx
	}

	scaleDown := NewScaleDown(autoscalingContext)

	return &StaticAutoscaler{
		AutoscalingContext:       autoscalingContext,
		ListerRegistry:           listerRegistry,
		lastScaleUpTime:          time.Now(),
		lastScaleDownFailedTrial: time.Now(),
		scaleDown:                scaleDown,
	}, nil
}

// CleanUp cleans up ToBeDeleted taints added by the previously run and then failed CA
func (a *StaticAutoscaler) CleanUp() {
	// CA can die at any time. Removing taints that might have been left from the previous run.
	if readyNodes, err := a.ReadyNodeLister().List(); err != nil {
		cleanToBeDeleted(readyNodes, a.AutoscalingContext.ClientSet, a.Recorder)
	}
}

// CloudProvider returns the cloud provider associated to this autoscaler
func (a *StaticAutoscaler) CloudProvider() cloudprovider.CloudProvider {
	return a.AutoscalingContext.CloudProvider
}

// RunOnce iterates over node groups and scales them up/down if necessary
func (a *StaticAutoscaler) RunOnce(currentTime time.Time) errors.AutoscalerError {
	readyNodeLister := a.ReadyNodeLister()
	allNodeLister := a.AllNodeLister()
	unschedulablePodLister := a.UnschedulablePodLister()
	scheduledPodLister := a.ScheduledPodLister()
	pdbLister := a.PodDisruptionBudgetLister()
	scaleDown := a.scaleDown
	autoscalingContext := a.AutoscalingContext
	runStart := time.Now()

	readyNodes, err := readyNodeLister.List()
	if err != nil {
		glog.Errorf("Failed to list ready nodes: %v", err)
		return errors.ToAutoscalerError(errors.ApiCallError, err)
	}
	if len(readyNodes) == 0 {
		glog.Warningf("No ready nodes in the cluster")
		scaleDown.CleanUpUnneededNodes()
		return nil
	}

	allNodes, err := allNodeLister.List()
	if err != nil {
		glog.Errorf("Failed to list all nodes: %v", err)
		return errors.ToAutoscalerError(errors.ApiCallError, err)
	}
	if len(allNodes) == 0 {
		glog.Warningf("No nodes in the cluster")
		scaleDown.CleanUpUnneededNodes()
		return nil
	}

	err = a.ClusterStateRegistry.UpdateNodes(allNodes, currentTime)
	if err != nil {
		glog.Errorf("Failed to update node registry: %v", err)
		scaleDown.CleanUpUnneededNodes()
		return errors.ToAutoscalerError(errors.CloudProviderError, err)
	}
	metrics.UpdateClusterState(a.ClusterStateRegistry)

	// Update status information when the loop is done (regardless of reason)
	defer func() {
		if autoscalingContext.WriteStatusConfigMap {
			status := a.ClusterStateRegistry.GetStatus(time.Now())
			utils.WriteStatusConfigMap(autoscalingContext.ClientSet, autoscalingContext.ConfigNamespace,
				status.GetReadableString(), a.AutoscalingContext.LogRecorder)
		}
	}()
	if !a.ClusterStateRegistry.IsClusterHealthy() {
		glog.Warning("Cluster is not ready for autoscaling")
		scaleDown.CleanUpUnneededNodes()
		return nil
	}

	metrics.UpdateDuration("updateClusterState", runStart)
	metrics.UpdateLastTime("autoscaling", time.Now())

	// Check if there are any nodes that failed to register in kuberentes
	// master.
	unregisteredNodes := a.ClusterStateRegistry.GetUnregisteredNodes()
	if len(unregisteredNodes) > 0 {
		glog.V(1).Infof("%d unregistered nodes present", len(unregisteredNodes))
		removedAny, err := removeOldUnregisteredNodes(unregisteredNodes, autoscalingContext, time.Now())
		// There was a problem with removing unregistered nodes. Retry in the next loop.
		if err != nil {
			if removedAny {
				glog.Warningf("Some unregistered nodes were removed, but got error: %v", err)
			} else {
				glog.Errorf("Failed to remove unregistered nodes: %v", err)

			}
			return errors.ToAutoscalerError(errors.CloudProviderError, err)
		}
		// Some nodes were removed. Let's skip this iteration, the next one should be better.
		if removedAny {
			glog.V(0).Infof("Some unregistered nodes were removed, skipping iteration")
			return nil
		}
	}

	// Check if there has been a constant difference between the number of nodes in k8s and
	// the number of nodes on the cloud provider side.
	// TODO: andrewskim - add protection for ready AWS nodes.
	fixedSomething, err := fixNodeGroupSize(autoscalingContext, time.Now())
	if err != nil {
		glog.Errorf("Failed to fix node group sizes: %v", err)
		return errors.ToAutoscalerError(errors.CloudProviderError, err)
	}
	if fixedSomething {
		glog.V(0).Infof("Some node group target size was fixed, skipping the iteration")
		return nil
	}

	allUnschedulablePods, err := unschedulablePodLister.List()
	if err != nil {
		glog.Errorf("Failed to list unscheduled pods: %v", err)
		return errors.ToAutoscalerError(errors.ApiCallError, err)
	}
	metrics.UpdateUnschedulablePodsCount(len(allUnschedulablePods))

	allScheduled, err := scheduledPodLister.List()
	if err != nil {
		glog.Errorf("Failed to list scheduled pods: %v", err)
		return errors.ToAutoscalerError(errors.ApiCallError, err)
	}

	// We need to reset all pods that have been marked as unschedulable not after
	// the newest node became available for the scheduler.
	allNodesAvailableTime := GetAllNodesAvailableTime(readyNodes)
	podsToReset, unschedulablePodsToHelp := SlicePodsByPodScheduledTime(allUnschedulablePods, allNodesAvailableTime)
	ResetPodScheduledCondition(a.AutoscalingContext.ClientSet, podsToReset)

	// We need to check whether pods marked as unschedulable are actually unschedulable.
	// This should prevent from adding unnecessary nodes. Example of such situation:
	// - CA and Scheduler has slightly different configuration
	// - Scheduler can't schedule a pod and marks it as unschedulable
	// - CA added a node which should help the pod
	// - Scheduler doesn't schedule the pod on the new node
	//   because according to it logic it doesn't fit there
	// - CA see the pod is still unschedulable, so it adds another node to help it
	//
	// With the check enabled the last point won't happen because CA will ignore a pod
	// which is supposed to schedule on an existing node.
	//
	// Without below check cluster might be unnecessary scaled up to the max allowed size
	// in the described situation.
	schedulablePodsPresent := false
	if a.VerifyUnschedulablePods {

		glog.V(4).Infof("Filtering out schedulables")
		newUnschedulablePodsToHelp := FilterOutSchedulable(unschedulablePodsToHelp, readyNodes, allScheduled,
			a.PredicateChecker)

		if len(newUnschedulablePodsToHelp) != len(unschedulablePodsToHelp) {
			glog.V(2).Info("Schedulable pods present")
			schedulablePodsPresent = true
		} else {
			glog.V(4).Info("No schedulable pods")
		}
		unschedulablePodsToHelp = newUnschedulablePodsToHelp
	}

	if len(unschedulablePodsToHelp) == 0 {
		glog.V(1).Info("No unschedulable pods")
	} else if a.MaxNodesTotal > 0 && len(readyNodes) >= a.MaxNodesTotal {
		glog.V(1).Info("Max total nodes in cluster reached")
	} else {
		scaleUpStart := time.Now()
		metrics.UpdateLastTime("scaleUp", scaleUpStart)

		daemonsets, err := a.ListerRegistry.DaemonSetLister().List()
		if err != nil {
			glog.Errorf("Failed to get daemonset list")
			return errors.ToAutoscalerError(errors.ApiCallError, err)
		}

		scaledUp, typedErr := ScaleUp(autoscalingContext, unschedulablePodsToHelp, readyNodes, daemonsets)

		metrics.UpdateDuration("scaleup", scaleUpStart)

		if typedErr != nil {
			glog.Errorf("Failed to scale up: %v", typedErr)
			return typedErr
		} else if scaledUp {
			a.lastScaleUpTime = time.Now()
			// No scale down in this iteration.
			return nil
		}
	}

	if a.ScaleDownEnabled {
		unneededStart := time.Now()

		pdbs, err := pdbLister.List()
		if err != nil {
			glog.Errorf("Failed to list pod disruption budgets: %v", err)
			return errors.ToAutoscalerError(errors.ApiCallError, err)
		}

		// In dry run only utilization is updated
		calculateUnneededOnly := a.lastScaleUpTime.Add(a.ScaleDownDelay).After(time.Now()) ||
			a.lastScaleDownFailedTrial.Add(a.ScaleDownTrialInterval).After(time.Now()) ||
			schedulablePodsPresent

		glog.V(4).Infof("Scale down status: unneededOnly=%v lastScaleUpTime=%s "+
			"lastScaleDownFailedTrail=%s schedulablePodsPresent=%v", calculateUnneededOnly,
			a.lastScaleUpTime, a.lastScaleDownFailedTrial, schedulablePodsPresent)

		glog.V(4).Infof("Calculating unneeded nodes")

		scaleDown.CleanUp(time.Now())
		managedNodes := getManagedNodes(autoscalingContext, allNodes)

		typedErr := scaleDown.UpdateUnneededNodes(allNodes, managedNodes, allScheduled, time.Now(), pdbs)
		if typedErr != nil {
			glog.Errorf("Failed to scale down: %v", typedErr)
			return typedErr
		}

		metrics.UpdateDuration("findUnneeded", unneededStart)

		for key, val := range scaleDown.unneededNodes {
			if glog.V(4) {
				glog.V(4).Infof("%s is unneeded since %s duration %s", key, val.String(), time.Now().Sub(val).String())
			}
		}

		if !calculateUnneededOnly {
			glog.V(4).Infof("Starting scale down")

			scaleDownStart := time.Now()
			metrics.UpdateLastTime("scaleDown", scaleDownStart)
			result, typedErr := scaleDown.TryToScaleDown(allNodes, allScheduled, pdbs)
			metrics.UpdateDuration("scaleDown", scaleDownStart)

			// TODO: revisit result handling
			if typedErr != nil {
				glog.Errorf("Failed to scale down: %v", err)
				return typedErr
			}
			if result == ScaleDownError || result == ScaleDownNoNodeDeleted {
				a.lastScaleDownFailedTrial = time.Now()
			}
		}
	}
	return nil
}

// ExitCleanUp removes status configmap.
func (a *StaticAutoscaler) ExitCleanUp() {
	if !a.AutoscalingContext.WriteStatusConfigMap {
		return
	}
	utils.DeleteStatusConfigMap(a.AutoscalingContext.ClientSet, a.AutoscalingContext.ConfigNamespace)
}
<commit_msg>change scope of findUnneeded metric<commit_after>/*
Copyright 2016 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package core

import (
	"time"

	"k8s.io/autoscaler/cluster-autoscaler/clusterstate/utils"
	"k8s.io/autoscaler/cluster-autoscaler/metrics"
	"k8s.io/autoscaler/cluster-autoscaler/simulator"
	"k8s.io/autoscaler/cluster-autoscaler/utils/errors"
	kube_util "k8s.io/autoscaler/cluster-autoscaler/utils/kubernetes"
	kube_record "k8s.io/client-go/tools/record"
	kube_client "k8s.io/kubernetes/pkg/client/clientset_generated/clientset"

	"github.com/golang/glog"
	"k8s.io/autoscaler/cluster-autoscaler/cloudprovider"
)

// StaticAutoscaler is an autoscaler which has all the core functionality of a CA but without the reconfiguration feature
type StaticAutoscaler struct {
	// AutoscalingContext consists of validated settings and options for this autoscaler
	*AutoscalingContext
	kube_util.ListerRegistry
	lastScaleUpTime          time.Time
	lastScaleDownFailedTrial time.Time
	scaleDown                *ScaleDown
}

// NewStaticAutoscaler creates an instance of Autoscaler filled with provided parameters
func NewStaticAutoscaler(opts AutoscalingOptions, predicateChecker *simulator.PredicateChecker,
	kubeClient kube_client.Interface, kubeEventRecorder kube_record.EventRecorder, listerRegistry kube_util.ListerRegistry) (*StaticAutoscaler, errors.AutoscalerError) {
	logRecorder, err := utils.NewStatusMapRecorder(kubeClient, opts.ConfigNamespace, kubeEventRecorder, opts.WriteStatusConfigMap)
	if err != nil {
		glog.Error("Failed to initialize status configmap, unable to write status events")
		// Get a dummy, so we can at least safely call the methods
		// TODO(maciekpytel): recover from this after successfull status configmap update?
		logRecorder, _ = utils.NewStatusMapRecorder(kubeClient, opts.ConfigNamespace, kubeEventRecorder, false)
	}
	autoscalingContext, errctx := NewAutoscalingContext(opts, predicateChecker, kubeClient, kubeEventRecorder, logRecorder, listerRegistry)
	if errctx != nil {
		return nil, errctx
	}

	scaleDown := NewScaleDown(autoscalingContext)

	return &StaticAutoscaler{
		AutoscalingContext:       autoscalingContext,
		ListerRegistry:           listerRegistry,
		lastScaleUpTime:          time.Now(),
		lastScaleDownFailedTrial: time.Now(),
		scaleDown:                scaleDown,
	}, nil
}

// CleanUp cleans up ToBeDeleted taints added by the previously run and then failed CA
func (a *StaticAutoscaler) CleanUp() {
	// CA can die at any time. Removing taints that might have been left from the previous run.
	if readyNodes, err := a.ReadyNodeLister().List(); err != nil {
		cleanToBeDeleted(readyNodes, a.AutoscalingContext.ClientSet, a.Recorder)
	}
}

// CloudProvider returns the cloud provider associated to this autoscaler
func (a *StaticAutoscaler) CloudProvider() cloudprovider.CloudProvider {
	return a.AutoscalingContext.CloudProvider
}

// RunOnce iterates over node groups and scales them up/down if necessary
func (a *StaticAutoscaler) RunOnce(currentTime time.Time) errors.AutoscalerError {
	readyNodeLister := a.ReadyNodeLister()
	allNodeLister := a.AllNodeLister()
	unschedulablePodLister := a.UnschedulablePodLister()
	scheduledPodLister := a.ScheduledPodLister()
	pdbLister := a.PodDisruptionBudgetLister()
	scaleDown := a.scaleDown
	autoscalingContext := a.AutoscalingContext
	runStart := time.Now()

	readyNodes, err := readyNodeLister.List()
	if err != nil {
		glog.Errorf("Failed to list ready nodes: %v", err)
		return errors.ToAutoscalerError(errors.ApiCallError, err)
	}
	if len(readyNodes) == 0 {
		glog.Warningf("No ready nodes in the cluster")
		scaleDown.CleanUpUnneededNodes()
		return nil
	}

	allNodes, err := allNodeLister.List()
	if err != nil {
		glog.Errorf("Failed to list all nodes: %v", err)
		return errors.ToAutoscalerError(errors.ApiCallError, err)
	}
	if len(allNodes) == 0 {
		glog.Warningf("No nodes in the cluster")
		scaleDown.CleanUpUnneededNodes()
		return nil
	}

	err = a.ClusterStateRegistry.UpdateNodes(allNodes, currentTime)
	if err != nil {
		glog.Errorf("Failed to update node registry: %v", err)
		scaleDown.CleanUpUnneededNodes()
		return errors.ToAutoscalerError(errors.CloudProviderError, err)
	}
	metrics.UpdateClusterState(a.ClusterStateRegistry)

	// Update status information when the loop is done (regardless of reason)
	defer func() {
		if autoscalingContext.WriteStatusConfigMap {
			status := a.ClusterStateRegistry.GetStatus(time.Now())
			utils.WriteStatusConfigMap(autoscalingContext.ClientSet, autoscalingContext.ConfigNamespace,
				status.GetReadableString(), a.AutoscalingContext.LogRecorder)
		}
	}()
	if !a.ClusterStateRegistry.IsClusterHealthy() {
		glog.Warning("Cluster is not ready for autoscaling")
		scaleDown.CleanUpUnneededNodes()
		return nil
	}

	metrics.UpdateDuration("updateClusterState", runStart)
	metrics.UpdateLastTime("autoscaling", time.Now())

	// Check if there are any nodes that failed to register in kuberentes
	// master.
	unregisteredNodes := a.ClusterStateRegistry.GetUnregisteredNodes()
	if len(unregisteredNodes) > 0 {
		glog.V(1).Infof("%d unregistered nodes present", len(unregisteredNodes))
		removedAny, err := removeOldUnregisteredNodes(unregisteredNodes, autoscalingContext, time.Now())
		// There was a problem with removing unregistered nodes. Retry in the next loop.
		if err != nil {
			if removedAny {
				glog.Warningf("Some unregistered nodes were removed, but got error: %v", err)
			} else {
				glog.Errorf("Failed to remove unregistered nodes: %v", err)

			}
			return errors.ToAutoscalerError(errors.CloudProviderError, err)
		}
		// Some nodes were removed. Let's skip this iteration, the next one should be better.
		if removedAny {
			glog.V(0).Infof("Some unregistered nodes were removed, skipping iteration")
			return nil
		}
	}

	// Check if there has been a constant difference between the number of nodes in k8s and
	// the number of nodes on the cloud provider side.
	// TODO: andrewskim - add protection for ready AWS nodes.
	fixedSomething, err := fixNodeGroupSize(autoscalingContext, time.Now())
	if err != nil {
		glog.Errorf("Failed to fix node group sizes: %v", err)
		return errors.ToAutoscalerError(errors.CloudProviderError, err)
	}
	if fixedSomething {
		glog.V(0).Infof("Some node group target size was fixed, skipping the iteration")
		return nil
	}

	allUnschedulablePods, err := unschedulablePodLister.List()
	if err != nil {
		glog.Errorf("Failed to list unscheduled pods: %v", err)
		return errors.ToAutoscalerError(errors.ApiCallError, err)
	}
	metrics.UpdateUnschedulablePodsCount(len(allUnschedulablePods))

	allScheduled, err := scheduledPodLister.List()
	if err != nil {
		glog.Errorf("Failed to list scheduled pods: %v", err)
		return errors.ToAutoscalerError(errors.ApiCallError, err)
	}

	// We need to reset all pods that have been marked as unschedulable not after
	// the newest node became available for the scheduler.
	allNodesAvailableTime := GetAllNodesAvailableTime(readyNodes)
	podsToReset, unschedulablePodsToHelp := SlicePodsByPodScheduledTime(allUnschedulablePods, allNodesAvailableTime)
	ResetPodScheduledCondition(a.AutoscalingContext.ClientSet, podsToReset)

	// We need to check whether pods marked as unschedulable are actually unschedulable.
	// This should prevent from adding unnecessary nodes. Example of such situation:
	// - CA and Scheduler has slightly different configuration
	// - Scheduler can't schedule a pod and marks it as unschedulable
	// - CA added a node which should help the pod
	// - Scheduler doesn't schedule the pod on the new node
	//   because according to it logic it doesn't fit there
	// - CA see the pod is still unschedulable, so it adds another node to help it
	//
	// With the check enabled the last point won't happen because CA will ignore a pod
	// which is supposed to schedule on an existing node.
	//
	// Without below check cluster might be unnecessary scaled up to the max allowed size
	// in the described situation.
	schedulablePodsPresent := false
	if a.VerifyUnschedulablePods {

		glog.V(4).Infof("Filtering out schedulables")
		newUnschedulablePodsToHelp := FilterOutSchedulable(unschedulablePodsToHelp, readyNodes, allScheduled,
			a.PredicateChecker)

		if len(newUnschedulablePodsToHelp) != len(unschedulablePodsToHelp) {
			glog.V(2).Info("Schedulable pods present")
			schedulablePodsPresent = true
		} else {
			glog.V(4).Info("No schedulable pods")
		}
		unschedulablePodsToHelp = newUnschedulablePodsToHelp
	}

	if len(unschedulablePodsToHelp) == 0 {
		glog.V(1).Info("No unschedulable pods")
	} else if a.MaxNodesTotal > 0 && len(readyNodes) >= a.MaxNodesTotal {
		glog.V(1).Info("Max total nodes in cluster reached")
	} else {
		scaleUpStart := time.Now()
		metrics.UpdateLastTime("scaleUp", scaleUpStart)

		daemonsets, err := a.ListerRegistry.DaemonSetLister().List()
		if err != nil {
			glog.Errorf("Failed to get daemonset list")
			return errors.ToAutoscalerError(errors.ApiCallError, err)
		}

		scaledUp, typedErr := ScaleUp(autoscalingContext, unschedulablePodsToHelp, readyNodes, daemonsets)

		metrics.UpdateDuration("scaleup", scaleUpStart)

		if typedErr != nil {
			glog.Errorf("Failed to scale up: %v", typedErr)
			return typedErr
		} else if scaledUp {
			a.lastScaleUpTime = time.Now()
			// No scale down in this iteration.
			return nil
		}
	}

	if a.ScaleDownEnabled {
		pdbs, err := pdbLister.List()
		if err != nil {
			glog.Errorf("Failed to list pod disruption budgets: %v", err)
			return errors.ToAutoscalerError(errors.ApiCallError, err)
		}

		unneededStart := time.Now()
		// In dry run only utilization is updated
		calculateUnneededOnly := a.lastScaleUpTime.Add(a.ScaleDownDelay).After(time.Now()) ||
			a.lastScaleDownFailedTrial.Add(a.ScaleDownTrialInterval).After(time.Now()) ||
			schedulablePodsPresent

		glog.V(4).Infof("Scale down status: unneededOnly=%v lastScaleUpTime=%s "+
			"lastScaleDownFailedTrail=%s schedulablePodsPresent=%v", calculateUnneededOnly,
			a.lastScaleUpTime, a.lastScaleDownFailedTrial, schedulablePodsPresent)

		glog.V(4).Infof("Calculating unneeded nodes")

		scaleDown.CleanUp(time.Now())
		managedNodes := getManagedNodes(autoscalingContext, allNodes)

		typedErr := scaleDown.UpdateUnneededNodes(allNodes, managedNodes, allScheduled, time.Now(), pdbs)
		if typedErr != nil {
			glog.Errorf("Failed to scale down: %v", typedErr)
			return typedErr
		}

		metrics.UpdateDuration("findUnneeded", unneededStart)

		for key, val := range scaleDown.unneededNodes {
			if glog.V(4) {
				glog.V(4).Infof("%s is unneeded since %s duration %s", key, val.String(), time.Now().Sub(val).String())
			}
		}

		if !calculateUnneededOnly {
			glog.V(4).Infof("Starting scale down")

			scaleDownStart := time.Now()
			metrics.UpdateLastTime("scaleDown", scaleDownStart)
			result, typedErr := scaleDown.TryToScaleDown(allNodes, allScheduled, pdbs)
			metrics.UpdateDuration("scaleDown", scaleDownStart)

			// TODO: revisit result handling
			if typedErr != nil {
				glog.Errorf("Failed to scale down: %v", err)
				return typedErr
			}
			if result == ScaleDownError || result == ScaleDownNoNodeDeleted {
				a.lastScaleDownFailedTrial = time.Now()
			}
		}
	}
	return nil
}

// ExitCleanUp removes status configmap.
func (a *StaticAutoscaler) ExitCleanUp() {
	if !a.AutoscalingContext.WriteStatusConfigMap {
		return
	}
	utils.DeleteStatusConfigMap(a.AutoscalingContext.ClientSet, a.AutoscalingContext.ConfigNamespace)
}
<|endoftext|>


<commit_before>package sudoku

type UniqueSum struct {
	positions []int
	total     int
}

func (u UniqueSum) Constrain(s *Sudoku, pos int, marked []bool) bool {
	if slicePos(u.positions, pos) == -1 {
		return true
	}
	total := 0
	myMark := make([]int, len(u.positions))
	unmarked := 0
	for _, p := range u.positions {
		if mp := s.data[p]; mp == 0 {
			unmarked++
		} else {
			if slicePos(myMark, mp) != -1 {
				return false
			}
			myMark = append(myMark, mp)
			marked[mp] = true
			total += mp
		}
	}
	left := u.total - total
	if left < 0 {
		return false
	}
	myNums := make([]int, 0, s.chars)
	for n, m := range marked {
		if !m {
			myNums = append(myNums, n)
		}
	}
	if len(myNums) < unmarked {
		return false
	}
	data := make([]int, 0, unmarked)
	marks := make([]bool, 0, s.chars+1)
	if !getCombinations(myNums, data, left, 0, marks) {
		return false
	}
	r := false
	for n, m := range marks {
		if !m {
			marked[n] = true
			r = true
		} else if !r && !marked[n] {
			r = true
		}
	}
	return r
}
func getCombinations(nums, data []int, addTo, from int, marks []bool) bool {
	if from == cap(data) {
		total := 0
		for _, n := range nums {
			total += n
		}
		if total == addTo {
			for _, n := range nums {
				marks[n] = true // ????
			}
			return true
		}
		return false
	}
	toRet := false
	for i := from; i < cap(data); i++ {
		data = append(data, nums[i])
		if getCombinations(nums, data, addTo, i+1, marks) {
			toRet = true
		}
		data = data[:len(data)-1]
	}
	return toRet
}
<commit_msg>Corrected UniqueSum<commit_after>package sudoku

type UniqueSum struct {
	positions []int
	total     int
}

func (u UniqueSum) Constrain(s *Sudoku, pos int, marked []bool) bool {
	if slicePos(u.positions, pos) == -1 {
		return true
	}
	total := 0
	myMark := make([]bool, s.chars+1)
	empty := 0
	for _, p := range u.positions {
		if mp := s.data[p]; mp == 0 {
			empty++
		} else {
			if myMark[mp] {
				return false
			}
			myMark[mp] = true
			marked[mp] = true
			total += mp
		}
	}
	remaining := u.total - total
	if remaining < 0 {
		return false
	}
	myNums := make([]int, 0, s.chars)
	for n, b := range myMark[1:] {
		if !b {
			myNums = append(myNums, n+1)
		}
	}
	data := make([]int, 0, empty)
	marks := make([]bool, s.chars+1)
	if !getCombinations(myNums, data, 0, remaining, marks) {
		return false
	}
	r := false
	for n, m := range marks {
		if !m {
			marked[n] = true
		} else if !r && !marked[n] {
			r = true
		}
	}
	return r
}

func getCombinations(nums, data []int, pos, remaining int, marks []bool) bool {
	if len(data) == cap(data) {
		if remaining == 0 {
			//fmt.Println(data)
			for _, n := range data {
				marks[n] = true
			}
			return true
		}
		return false
	}
	toRet := false
	o := data
	for i := pos; i < len(nums); i++ {
		if nums[i] > remaining {
			continue
		}
		data = append(data, nums[i])
		if getCombinations(nums, data, i+1, remaining-nums[i], marks) {
			toRet = true
		}
		data = o
	}
	return toRet
}
<|endoftext|>


<commit_before>package requests

import (
	"errors"
	"fmt"
	"reflect"
	"strconv"
)

// set is a simple slice of unique strings.
type set []string

// add appends a variadic amount of strings to a set, returning the
// resulting set.  Duplicates will only exist once in the resulting
// set.
func (s set) add(values ...string) set {
	for _, newValue := range values {
		exists := false
		for _, value := range s {
			if newValue == value {
				exists = true
				break
			}
		}
		if !exists {
			s = append(s, newValue)
		}
	}
	return s
}

// UnmarshalReplace performs the same process as Unmarshal, except
// that values not found in the request will be updated to their zero
// value.  For example, if foo.Bar == "baz" and foo.Bar has no
// corresponding data in a request, Unmarshal would leave it as "baz",
// but UnmarshalReplace will update it to "".
//
// Exceptions are made for unexported fields and fields which are
// found to have a name of "-".  Those are left alone.
func (request *Request) UnmarshalReplace(target interface{}) error {
	return request.unmarshal(target, true)
}

// Unmarshal unmarshals a request to a struct, using field tags to
// locate corresponding values in the request and check/parse them
// before assigning them to struct fields.  It acts similar to json's
// Unmarshal when used on a struct, but works with any codec
// registered with AddCodec().
//
// Field tags are used as follows:
//
// * All field tags are considered to be of the format
// name,option1,option2,...
//
// * Options will *only* be parsed from the "request" tag.
//
// * By default, name will only be checked in the "request" tag, but
// you can add fallback tag names using AddFallbackTag.
//
// * If no non-empty name is found using field tags, the lowercase
// field name will be used instead.
//
// * Once a name is found, if the name is "-", then the field will be
// treated as if it does not exist.
//
// For an explanation on how options work, see the documentation for
// RegisterOption.  For a list of tag options built in to this
// library, see the options package in this package.
//
// Fields which have no data in the request will be left as their
// current value.  They will still be passed through the option parser
// for the purposes of options like "required".
//
// Fields which implement Receiver will have their Receive method
// called using the value from the request after calling all
// OptionFuncs matching the field's tag options.
//
// An error will be returned if the target type is not a pointer to a
// struct, or if the target implements PreUnmarshaller, Unmarshaller,
// or PostUnmarshaller and the corresponding methods fail.  An
// UnusedFields error will be returned if fields in the request had no
// corresponding fields on the target struct.
//
// Any errors encountered while attempting to apply input values to
// the target's fields will be stored in an error of type InputErrors.
// At the end of the Unmarshal process, the InputErrors error will be
// returned if any errors were encountered.
//
// A simple example:
//
//     type Example struct {
//         Foo string `request:",required"`
//         Bar string `response:"baz"`
//         Baz string `response:"-"`
//         Bacon string `response:"-" request:"bacon,required"`
//     }
//
//     func CreateExample(request *http.Request) (*Example, error) {
//         target := new(Example)
//         if err := requests.New(request).Unmarshal(target); err != nil {
//             if inputErrs, ok := err.(InputErrors); ok {
//                 // inputErrs is a map of input names to error
//                 // messages, so send them to a function to turn
//                 // them into a proper user-friendly error message.
//                 return nil, userErrors(inputErrs)
//             }
//             return nil, err
//         }
//         return target, nil
//     }
//
func (request *Request) Unmarshal(target interface{}) error {
	return request.unmarshal(target, false)
}

// unmarshal performes all of the logic for Unmarshal and
// UnmarshalReplace.
func (request *Request) unmarshal(target interface{}, replace bool) (unmarshalErr error) {
	targetValue := reflect.ValueOf(target)
	if targetValue.Kind() != reflect.Ptr || targetValue.Elem().Kind() != reflect.Struct {
		return errors.New("The value passed to Unmarshal must be a pointer to a struct")
	}
	targetValue = targetValue.Elem()
	params, err := request.Params()
	if err != nil {
		return err
	}

	if preUnmarshaller, ok := target.(PreUnmarshaller); ok {
		if unmarshalErr = preUnmarshaller.PreUnmarshal(); unmarshalErr != nil {
			return
		}
	}
	if postUnmarshaller, ok := target.(PostUnmarshaller); ok {
		defer func() {
			if unmarshalErr == nil {
				unmarshalErr = postUnmarshaller.PostUnmarshal()
			}
		}()
	}
	if unmarshaller, ok := target.(Unmarshaller); ok {
		return unmarshaller.Unmarshal(params)
	}

	matchedFields, inputErrs := unmarshalToValue(params, targetValue, replace)
	if len(inputErrs) > 0 {
		return inputErrs
	}

	unused := &UnusedFields{
		params:  params,
		matched: matchedFields,
	}
	if unused.HasMissing() {
		return unused
	}
	return nil
}

// unmarshalToValue is a helper for UnmarshalParams, which keeps track
// of the total number of fields matched in a request and which fields
// were missing from a request.
func unmarshalToValue(params map[string]interface{}, targetValue reflect.Value, replace bool) (matchedFields set, parseErrs InputErrors) {
	matchedFields = make(set, 0, len(params))
	parseErrs = make(InputErrors)
	defer func() {
		// Clean up any nil errors from the error map.
		parseErrs = parseErrs.Errors()
	}()

	targetType := targetValue.Type()
	for i := 0; i < targetValue.NumField(); i++ {
		fieldValue := targetValue.Field(i)
		field := targetType.Field(i)
		if field.Anonymous {
			// Ignore non-struct anonymous fields, but treat fields in
			// struct or struct pointer anonymous fields as if they
			// were fields on the child struct.
			if fieldValue.Kind() == reflect.Ptr {
				fieldValue = fieldValue.Elem()
			}
			if fieldValue.Kind() == reflect.Struct {
				embeddedFields, newErrs := unmarshalToValue(params, fieldValue, replace)
				if newErrs != nil {
					// Override input errors in the anonymous field
					// with input errors in the child.  Non-nil
					// errors from anonymous fields will be
					// overwritten with nil errors from overriding
					// child fields.
					parseErrs = newErrs.Merge(parseErrs)
				}
				matchedFields = matchedFields.add(embeddedFields...)
			}
			continue
		}

		// Skip unexported fields
		if field.PkgPath == "" {
			name := name(field)
			if name == "-" {
				continue
			}

			valueInter, fromParams := params[name]
			var value reflect.Value
			if fromParams {
				value = reflect.ValueOf(valueInter)
				matchedFields = matchedFields.add(name)
			} else {
				// If we're not replacing the value, use the field's
				// current value.  If we are, use the field's zero
				// value.
				zero := reflect.Zero(fieldValue.Type())
				if replace {
					value = zero
				} else {
					value = fieldValue
				}
				if value == zero {
					// The value is empty, so see if its default can
					// be loaded.
					if defaulter, ok := fieldValue.Interface().(Defaulter); ok {
						value = reflect.ValueOf(defaulter.DefaultValue())
					}
				}
			}
			var optionValue interface{}
			if value.IsValid() {
				optionValue = value.Interface()
			}
			newVal, inputErr := ApplyOptions(field, fieldValue.Interface(), optionValue)
			if parseErrs.Set(name, inputErr) {
				continue
			}
			value = reflect.ValueOf(newVal)
			parseErrs.Set(name, setValue(fieldValue, value, fromParams))
		}
	}
	return
}

// isNil returns true if value.IsValid() returns false or if
// value.IsNil() returns true.  Returns false otherwise.  Recovers
// panics from value.IsNil().
func isNil(value reflect.Value) bool {
	defer func() {
		recover()
	}()
	if !value.IsValid() {
		return true
	}
	if value.IsNil() {
		return true
	}
	return false
}

// assignNil takes a target and value and handles nil assignment.  If
// value is nil or invalid, target will be assigned nil.  If value is
// non-nil and target is a nil pointer, it will be initialized.
// Returns whether or not value evaluates to nil, and any errors
// encountered while attempting assignment.
func assignNil(target, value reflect.Value) (valueIsNil bool, err error) {
	defer func() {
		if r := recover(); r != nil {
			err = fmt.Errorf("Nil value found, but type %s cannot be nil.", target.Type().Name())
		}
	}()

	if valueIsNil = isNil(value); valueIsNil {
		// target.IsNil() will panic if target's zero value is
		// non-nil.
		if !target.IsNil() {
			target.Set(reflect.Zero(target.Type()))
		}
		return
	}

	if target.Kind() == reflect.Ptr && target.IsNil() {
		target.Set(reflect.New(target.Type().Elem()))
	}
	return
}

func callReceivers(target reflect.Value, value interface{}) (receiverFound bool, err error) {
	preReceiver, hasPreReceive := target.Interface().(PreReceiver)
	receiver, hasReceive := target.Interface().(Receiver)
	postReceiver, hasPostReceive := target.Interface().(PostReceiver)
	if target.CanAddr() {
		// If interfaces weren't found, try again with the pointer
		targetPtr := target.Addr().Interface()
		if !hasPreReceive {
			preReceiver, hasPreReceive = targetPtr.(PreReceiver)
		}
		if !hasReceive {
			receiver, hasReceive = targetPtr.(Receiver)
		}
		if !hasPostReceive {
			postReceiver, hasPostReceive = targetPtr.(PostReceiver)
		}
	}
	receiverFound = hasReceive

	if hasPreReceive {
		if err = preReceiver.PreReceive(); err != nil {
			return
		}
	}
	if hasPostReceive {
		defer func() {
			if err == nil {
				err = postReceiver.PostReceive()
			}
		}()
	}
	if hasReceive {
		err = receiver.Receive(value)
	}
	return
}

// setValue takes a target and a value, and updates the target to
// match the value.
func setValue(target, value reflect.Value, fromRequest bool) (parseErr error) {
	if isNil, err := assignNil(target, value); isNil || err != nil {
		return err
	}

	// Only worry about the receive methods if the value is from a
	// request.
	if fromRequest {
		if receiverFound, err := callReceivers(target, value.Interface()); err != nil || receiverFound {
			return err
		}
	}

	for target.Kind() == reflect.Ptr {
		target = target.Elem()
	}
	switch target.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		parseErr = setInt(target, value.Interface())
	case reflect.Float32, reflect.Float64:
		parseErr = setFloat(target, value.Interface())
	default:
		inputType := value.Type()
		if !inputType.ConvertibleTo(target.Type()) {
			return fmt.Errorf("Cannot convert value of type %s to type %s",
				inputType.Name(), target.Type().Name())
		}
		target.Set(value.Convert(target.Type()))
	}
	return
}

func setInt(target reflect.Value, value interface{}) error {
	switch src := value.(type) {
	case string:
		intVal, err := strconv.ParseInt(src, 10, 64)
		if err != nil {
			return err
		}
		target.SetInt(intVal)
	case int:
		target.SetInt(int64(src))
	case int8:
		target.SetInt(int64(src))
	case int16:
		target.SetInt(int64(src))
	case int32:
		target.SetInt(int64(src))
	case int64:
		target.SetInt(src)
	case float32:
		target.SetInt(int64(src))
	case float64:
		target.SetInt(int64(src))
	}
	return nil
}

func setFloat(target reflect.Value, value interface{}) error {
	switch src := value.(type) {
	case string:
		floatVal, err := strconv.ParseFloat(src, 64)
		if err != nil {
			return err
		}
		target.SetFloat(floatVal)
	case int:
		target.SetFloat(float64(src))
	case int8:
		target.SetFloat(float64(src))
	case int16:
		target.SetFloat(float64(src))
	case int32:
		target.SetFloat(float64(src))
	case int64:
		target.SetFloat(float64(src))
	case float32:
		target.SetFloat(float64(src))
	case float64:
		target.SetFloat(src)
	}
	return nil
}
<commit_msg>Fix for pointer values being assigned using input.Convert(target.Type())<commit_after>package requests

import (
	"errors"
	"fmt"
	"reflect"
	"strconv"
)

// set is a simple slice of unique strings.
type set []string

// add appends a variadic amount of strings to a set, returning the
// resulting set.  Duplicates will only exist once in the resulting
// set.
func (s set) add(values ...string) set {
	for _, newValue := range values {
		exists := false
		for _, value := range s {
			if newValue == value {
				exists = true
				break
			}
		}
		if !exists {
			s = append(s, newValue)
		}
	}
	return s
}

// UnmarshalReplace performs the same process as Unmarshal, except
// that values not found in the request will be updated to their zero
// value.  For example, if foo.Bar == "baz" and foo.Bar has no
// corresponding data in a request, Unmarshal would leave it as "baz",
// but UnmarshalReplace will update it to "".
//
// Exceptions are made for unexported fields and fields which are
// found to have a name of "-".  Those are left alone.
func (request *Request) UnmarshalReplace(target interface{}) error {
	return request.unmarshal(target, true)
}

// Unmarshal unmarshals a request to a struct, using field tags to
// locate corresponding values in the request and check/parse them
// before assigning them to struct fields.  It acts similar to json's
// Unmarshal when used on a struct, but works with any codec
// registered with AddCodec().
//
// Field tags are used as follows:
//
// * All field tags are considered to be of the format
// name,option1,option2,...
//
// * Options will *only* be parsed from the "request" tag.
//
// * By default, name will only be checked in the "request" tag, but
// you can add fallback tag names using AddFallbackTag.
//
// * If no non-empty name is found using field tags, the lowercase
// field name will be used instead.
//
// * Once a name is found, if the name is "-", then the field will be
// treated as if it does not exist.
//
// For an explanation on how options work, see the documentation for
// RegisterOption.  For a list of tag options built in to this
// library, see the options package in this package.
//
// Fields which have no data in the request will be left as their
// current value.  They will still be passed through the option parser
// for the purposes of options like "required".
//
// Fields which implement Receiver will have their Receive method
// called using the value from the request after calling all
// OptionFuncs matching the field's tag options.
//
// An error will be returned if the target type is not a pointer to a
// struct, or if the target implements PreUnmarshaller, Unmarshaller,
// or PostUnmarshaller and the corresponding methods fail.  An
// UnusedFields error will be returned if fields in the request had no
// corresponding fields on the target struct.
//
// Any errors encountered while attempting to apply input values to
// the target's fields will be stored in an error of type InputErrors.
// At the end of the Unmarshal process, the InputErrors error will be
// returned if any errors were encountered.
//
// A simple example:
//
//     type Example struct {
//         Foo string `request:",required"`
//         Bar string `response:"baz"`
//         Baz string `response:"-"`
//         Bacon string `response:"-" request:"bacon,required"`
//     }
//
//     func CreateExample(request *http.Request) (*Example, error) {
//         target := new(Example)
//         if err := requests.New(request).Unmarshal(target); err != nil {
//             if inputErrs, ok := err.(InputErrors); ok {
//                 // inputErrs is a map of input names to error
//                 // messages, so send them to a function to turn
//                 // them into a proper user-friendly error message.
//                 return nil, userErrors(inputErrs)
//             }
//             return nil, err
//         }
//         return target, nil
//     }
//
func (request *Request) Unmarshal(target interface{}) error {
	return request.unmarshal(target, false)
}

// unmarshal performes all of the logic for Unmarshal and
// UnmarshalReplace.
func (request *Request) unmarshal(target interface{}, replace bool) (unmarshalErr error) {
	targetValue := reflect.ValueOf(target)
	if targetValue.Kind() != reflect.Ptr || targetValue.Elem().Kind() != reflect.Struct {
		return errors.New("The value passed to Unmarshal must be a pointer to a struct")
	}
	targetValue = targetValue.Elem()
	params, err := request.Params()
	if err != nil {
		return err
	}

	if preUnmarshaller, ok := target.(PreUnmarshaller); ok {
		if unmarshalErr = preUnmarshaller.PreUnmarshal(); unmarshalErr != nil {
			return
		}
	}
	if postUnmarshaller, ok := target.(PostUnmarshaller); ok {
		defer func() {
			if unmarshalErr == nil {
				unmarshalErr = postUnmarshaller.PostUnmarshal()
			}
		}()
	}
	if unmarshaller, ok := target.(Unmarshaller); ok {
		return unmarshaller.Unmarshal(params)
	}

	matchedFields, inputErrs := unmarshalToValue(params, targetValue, replace)
	if len(inputErrs) > 0 {
		return inputErrs
	}

	unused := &UnusedFields{
		params:  params,
		matched: matchedFields,
	}
	if unused.HasMissing() {
		return unused
	}
	return nil
}

// unmarshalToValue is a helper for UnmarshalParams, which keeps track
// of the total number of fields matched in a request and which fields
// were missing from a request.
func unmarshalToValue(params map[string]interface{}, targetValue reflect.Value, replace bool) (matchedFields set, parseErrs InputErrors) {
	matchedFields = make(set, 0, len(params))
	parseErrs = make(InputErrors)
	defer func() {
		// Clean up any nil errors from the error map.
		parseErrs = parseErrs.Errors()
	}()

	targetType := targetValue.Type()
	for i := 0; i < targetValue.NumField(); i++ {
		fieldValue := targetValue.Field(i)
		field := targetType.Field(i)
		if field.Anonymous {
			// Ignore non-struct anonymous fields, but treat fields in
			// struct or struct pointer anonymous fields as if they
			// were fields on the child struct.
			if fieldValue.Kind() == reflect.Ptr {
				fieldValue = fieldValue.Elem()
			}
			if fieldValue.Kind() == reflect.Struct {
				embeddedFields, newErrs := unmarshalToValue(params, fieldValue, replace)
				if newErrs != nil {
					// Override input errors in the anonymous field
					// with input errors in the child.  Non-nil
					// errors from anonymous fields will be
					// overwritten with nil errors from overriding
					// child fields.
					parseErrs = newErrs.Merge(parseErrs)
				}
				matchedFields = matchedFields.add(embeddedFields...)
			}
			continue
		}

		// Skip unexported fields
		if field.PkgPath == "" {
			name := name(field)
			if name == "-" {
				continue
			}

			valueInter, fromParams := params[name]
			var value reflect.Value
			if fromParams {
				value = reflect.ValueOf(valueInter)
				matchedFields = matchedFields.add(name)
			} else {
				// If we're not replacing the value, use the field's
				// current value.  If we are, use the field's zero
				// value.
				zero := reflect.Zero(fieldValue.Type())
				if replace {
					value = zero
				} else {
					value = fieldValue
				}
				if value == zero {
					// The value is empty, so see if its default can
					// be loaded.
					if defaulter, ok := fieldValue.Interface().(Defaulter); ok {
						value = reflect.ValueOf(defaulter.DefaultValue())
					}
				}
			}
			var optionValue interface{}
			if value.IsValid() {
				optionValue = value.Interface()
			}
			newVal, inputErr := ApplyOptions(field, fieldValue.Interface(), optionValue)
			if parseErrs.Set(name, inputErr) {
				continue
			}
			value = reflect.ValueOf(newVal)
			parseErrs.Set(name, setValue(fieldValue, value, fromParams))
		}
	}
	return
}

// isNil returns true if value.IsValid() returns false or if
// value.IsNil() returns true.  Returns false otherwise.  Recovers
// panics from value.IsNil().
func isNil(value reflect.Value) bool {
	defer func() {
		recover()
	}()
	if !value.IsValid() {
		return true
	}
	if value.IsNil() {
		return true
	}
	return false
}

// assignNil takes a target and value and handles nil assignment.  If
// value is nil or invalid, target will be assigned nil.  If value is
// non-nil and target is a nil pointer, it will be initialized.
// Returns whether or not value evaluates to nil, and any errors
// encountered while attempting assignment.
func assignNil(target, value reflect.Value) (valueIsNil bool, err error) {
	defer func() {
		if r := recover(); r != nil {
			err = fmt.Errorf("Nil value found, but type %s cannot be nil.", target.Type().Name())
		}
	}()

	if valueIsNil = isNil(value); valueIsNil {
		// target.IsNil() will panic if target's zero value is
		// non-nil.
		if !target.IsNil() {
			target.Set(reflect.Zero(target.Type()))
		}
		return
	}

	if target.Kind() == reflect.Ptr && target.IsNil() {
		target.Set(reflect.New(target.Type().Elem()))
	}
	return
}

func callReceivers(target reflect.Value, value interface{}) (receiverFound bool, err error) {
	preReceiver, hasPreReceive := target.Interface().(PreReceiver)
	receiver, hasReceive := target.Interface().(Receiver)
	postReceiver, hasPostReceive := target.Interface().(PostReceiver)
	if target.CanAddr() {
		// If interfaces weren't found, try again with the pointer
		targetPtr := target.Addr().Interface()
		if !hasPreReceive {
			preReceiver, hasPreReceive = targetPtr.(PreReceiver)
		}
		if !hasReceive {
			receiver, hasReceive = targetPtr.(Receiver)
		}
		if !hasPostReceive {
			postReceiver, hasPostReceive = targetPtr.(PostReceiver)
		}
	}
	receiverFound = hasReceive

	if hasPreReceive {
		if err = preReceiver.PreReceive(); err != nil {
			return
		}
	}
	if hasPostReceive {
		defer func() {
			if err == nil {
				err = postReceiver.PostReceive()
			}
		}()
	}
	if hasReceive {
		err = receiver.Receive(value)
	}
	return
}

// setValue takes a target and a value, and updates the target to
// match the value.
func setValue(target, value reflect.Value, fromRequest bool) (parseErr error) {
	if isNil, err := assignNil(target, value); isNil || err != nil {
		return err
	}

	// Only worry about the receive methods if the value is from a
	// request.
	if fromRequest {
		if receiverFound, err := callReceivers(target, value.Interface()); err != nil || receiverFound {
			return err
		}
	}

	for target.Kind() == reflect.Ptr {
		target = target.Elem()
	}
	switch target.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		parseErr = setInt(target, value.Interface())
	case reflect.Float32, reflect.Float64:
		parseErr = setFloat(target, value.Interface())
	default:
		for value.Kind() == reflect.Ptr {
			value = value.Elem()
		}
		inputType := value.Type()
		if !inputType.ConvertibleTo(target.Type()) {
			return fmt.Errorf("Cannot convert value of type %s to type %s",
				inputType.Name(), target.Type().Name())
		}
		target.Set(value.Convert(target.Type()))
	}
	return
}

func setInt(target reflect.Value, value interface{}) error {
	switch src := value.(type) {
	case string:
		intVal, err := strconv.ParseInt(src, 10, 64)
		if err != nil {
			return err
		}
		target.SetInt(intVal)
	case int:
		target.SetInt(int64(src))
	case int8:
		target.SetInt(int64(src))
	case int16:
		target.SetInt(int64(src))
	case int32:
		target.SetInt(int64(src))
	case int64:
		target.SetInt(src)
	case float32:
		target.SetInt(int64(src))
	case float64:
		target.SetInt(int64(src))
	}
	return nil
}

func setFloat(target reflect.Value, value interface{}) error {
	switch src := value.(type) {
	case string:
		floatVal, err := strconv.ParseFloat(src, 64)
		if err != nil {
			return err
		}
		target.SetFloat(floatVal)
	case int:
		target.SetFloat(float64(src))
	case int8:
		target.SetFloat(float64(src))
	case int16:
		target.SetFloat(float64(src))
	case int32:
		target.SetFloat(float64(src))
	case int64:
		target.SetFloat(float64(src))
	case float32:
		target.SetFloat(float64(src))
	case float64:
		target.SetFloat(src)
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"os/signal"
	"syscall"

	"bazil.org/fuse"
	"bazil.org/fuse/fs"

	"github.com/jessevdk/go-flags"
)

// Options are global settings.
type Options struct {
	Seed int `long:"seed"                      description:"initial random seed"`

	mountpoint string
}

var opts = Options{}
var parser = flags.NewParser(&opts, flags.HelpFlag|flags.PassDoubleDash)

var exitRequested = make(chan struct{})

func init() {
	parser.Usage = "mountpoint"
	c := make(chan os.Signal)
	signal.Notify(c, syscall.SIGINT)

	go cleanupHandler(c)
}

func cleanupHandler(c <-chan os.Signal) {
	for range c {
		fmt.Println("Interrupt received, cleaning up")
		close(exitRequested)
	}
}

func mount(opts Options) error {
	conn, err := fuse.Mount(
		opts.mountpoint,
		fuse.ReadOnly(),
		fuse.FSName("fakedatafs"),
	)
	if err != nil {
		return err
	}

	root := fs.Tree{}

	// root.Add("snapshots", fuse.NewSnapshotsDir(repo, cmd.Root))

	// cmd.global.Printf("Now serving %s at %s\n", repo.Backend().Location(), mountpoint)
	// cmd.global.Printf("Don't forget to umount after quitting!\n")

	// AddCleanupHandler(func() error {
	// 	return fuse.Unmount(mountpoint)
	// })

	// cmd.ready <- struct{}{}

	err = fs.Serve(conn, &root)
	if err != nil {
		return err
	}

	<-conn.Ready
	err = conn.MountError
	if err != nil {
		fmt.Fprintf(os.Stderr, "mount failed: %v\n", err)
		return fuse.Unmount(opts.mountpoint)
	}

	fmt.Printf("successfully mounted fakedatafs at %v\n", opts.mountpoint)

	<-exitRequested

	fmt.Printf("umounting...\n")
	return fuse.Unmount(opts.mountpoint)
}

func main() {
	args, err := parser.Parse()
	if e, ok := err.(*flags.Error); ok && e.Type == flags.ErrHelp {
		parser.WriteHelp(os.Stdout)
		os.Exit(0)
	}

	if err != nil {
		fmt.Fprintf(os.Stderr, "%v\n", err)
	}

	if err != nil {
		os.Exit(1)
	}

	if len(args) == 0 {
		parser.WriteHelp(os.Stderr)
		os.Exit(1)
	}

	opts.mountpoint = args[0]
	err = mount(opts)
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		os.Exit(2)
	}
}
<commit_msg>Add option to print the version<commit_after>package main

import (
	"fmt"
	"os"
	"os/signal"
	"runtime"
	"syscall"

	"bazil.org/fuse"
	"bazil.org/fuse/fs"

	"github.com/jessevdk/go-flags"
)

var (
	version    = "compiled manually"
	compiledAt = "unknown"
)

// Options are global settings.
type Options struct {
	Seed    int  `long:"seed"                  description:"initial random seed"`
	Version bool `long:"version" short:"v"     description:"print version number"`

	mountpoint string
}

var opts = Options{}
var parser = flags.NewParser(&opts, flags.HelpFlag|flags.PassDoubleDash)

var exitRequested = make(chan struct{})

func init() {
	parser.Usage = "mountpoint"
	c := make(chan os.Signal)
	signal.Notify(c, syscall.SIGINT)

	go cleanupHandler(c)
}

func cleanupHandler(c <-chan os.Signal) {
	for range c {
		fmt.Println("Interrupt received, cleaning up")
		close(exitRequested)
	}
}

func mount(opts Options) error {
	conn, err := fuse.Mount(
		opts.mountpoint,
		fuse.ReadOnly(),
		fuse.FSName("fakedatafs"),
	)
	if err != nil {
		return err
	}

	root := fs.Tree{}

	// root.Add("snapshots", fuse.NewSnapshotsDir(repo, cmd.Root))

	// cmd.global.Printf("Now serving %s at %s\n", repo.Backend().Location(), mountpoint)
	// cmd.global.Printf("Don't forget to umount after quitting!\n")

	// AddCleanupHandler(func() error {
	// 	return fuse.Unmount(mountpoint)
	// })

	// cmd.ready <- struct{}{}

	err = fs.Serve(conn, &root)
	if err != nil {
		return err
	}

	<-conn.Ready
	err = conn.MountError
	if err != nil {
		fmt.Fprintf(os.Stderr, "mount failed: %v\n", err)
		return fuse.Unmount(opts.mountpoint)
	}

	fmt.Printf("successfully mounted fakedatafs at %v\n", opts.mountpoint)

	<-exitRequested

	fmt.Printf("umounting...\n")
	return fuse.Unmount(opts.mountpoint)
}

func main() {
	args, err := parser.Parse()
	if e, ok := err.(*flags.Error); ok && e.Type == flags.ErrHelp {
		parser.WriteHelp(os.Stdout)
		os.Exit(0)
	}

	if err != nil {
		fmt.Fprintf(os.Stderr, "%v\n", err)
	}

	if err != nil {
		os.Exit(1)
	}

	if opts.Version {
		fmt.Printf("version %v, compiled at %v using %v\n", version, compiledAt, runtime.Version())
		return
	}

	if len(args) == 0 {
		parser.WriteHelp(os.Stderr)
		os.Exit(1)
	}

	opts.mountpoint = args[0]
	err = mount(opts)
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		os.Exit(2)
	}
}
<|endoftext|>


<commit_before>// This file was auto-generated by the veyron vdl tool.
// Source: fortune.vdl

package fortune

import (
	"veyron.io/veyron/veyron2/security"

	// The non-user imports are prefixed with "_gen_" to prevent collisions.
	_gen_veyron2 "veyron.io/veyron/veyron2"
	_gen_context "veyron.io/veyron/veyron2/context"
	_gen_ipc "veyron.io/veyron/veyron2/ipc"
	_gen_naming "veyron.io/veyron/veyron2/naming"
	_gen_vdlutil "veyron.io/veyron/veyron2/vdl/vdlutil"
	_gen_wiretype "veyron.io/veyron/veyron2/wiretype"
)

// TODO(toddw): Remove this line once the new signature support is done.
// It corrects a bug where _gen_wiretype is unused in VDL pacakges where only
// bootstrap types are used on interfaces.
const _ = _gen_wiretype.TypeIDInvalid

// Fortune allows clients to Get and Add fortune strings.
// Fortune is the interface the client binds and uses.
// Fortune_ExcludingUniversal is the interface without internal framework-added methods
// to enable embedding without method collisions.  Not to be used directly by clients.
type Fortune_ExcludingUniversal interface {
	// Get returns a random fortune.
	Get(ctx _gen_context.T, opts ..._gen_ipc.CallOpt) (reply string, err error)
	// Add stores a fortune in the set used by Get.
	Add(ctx _gen_context.T, Fortune string, opts ..._gen_ipc.CallOpt) (err error)
}
type Fortune interface {
	_gen_ipc.UniversalServiceMethods
	Fortune_ExcludingUniversal
}

// FortuneService is the interface the server implements.
type FortuneService interface {

	// Get returns a random fortune.
	Get(context _gen_ipc.ServerContext) (reply string, err error)
	// Add stores a fortune in the set used by Get.
	Add(context _gen_ipc.ServerContext, Fortune string) (err error)
}

// BindFortune returns the client stub implementing the Fortune
// interface.
//
// If no _gen_ipc.Client is specified, the default _gen_ipc.Client in the
// global Runtime is used.
func BindFortune(name string, opts ..._gen_ipc.BindOpt) (Fortune, error) {
	var client _gen_ipc.Client
	switch len(opts) {
	case 0:
		// Do nothing.
	case 1:
		if clientOpt, ok := opts[0].(_gen_ipc.Client); opts[0] == nil || ok {
			client = clientOpt
		} else {
			return nil, _gen_vdlutil.ErrUnrecognizedOption
		}
	default:
		return nil, _gen_vdlutil.ErrTooManyOptionsToBind
	}
	stub := &clientStubFortune{defaultClient: client, name: name}

	return stub, nil
}

// NewServerFortune creates a new server stub.
//
// It takes a regular server implementing the FortuneService
// interface, and returns a new server stub.
func NewServerFortune(server FortuneService) interface{} {
	return &ServerStubFortune{
		service: server,
	}
}

// clientStubFortune implements Fortune.
type clientStubFortune struct {
	defaultClient _gen_ipc.Client
	name          string
}

func (__gen_c *clientStubFortune) client(ctx _gen_context.T) _gen_ipc.Client {
	if __gen_c.defaultClient != nil {
		return __gen_c.defaultClient
	}
	return _gen_veyron2.RuntimeFromContext(ctx).Client()
}

func (__gen_c *clientStubFortune) Get(ctx _gen_context.T, opts ..._gen_ipc.CallOpt) (reply string, err error) {
	var call _gen_ipc.Call
	if call, err = __gen_c.client(ctx).StartCall(ctx, __gen_c.name, "Get", nil, opts...); err != nil {
		return
	}
	if ierr := call.Finish(&reply, &err); ierr != nil {
		err = ierr
	}
	return
}

func (__gen_c *clientStubFortune) Add(ctx _gen_context.T, Fortune string, opts ..._gen_ipc.CallOpt) (err error) {
	var call _gen_ipc.Call
	if call, err = __gen_c.client(ctx).StartCall(ctx, __gen_c.name, "Add", []interface{}{Fortune}, opts...); err != nil {
		return
	}
	if ierr := call.Finish(&err); ierr != nil {
		err = ierr
	}
	return
}

func (__gen_c *clientStubFortune) UnresolveStep(ctx _gen_context.T, opts ..._gen_ipc.CallOpt) (reply []string, err error) {
	var call _gen_ipc.Call
	if call, err = __gen_c.client(ctx).StartCall(ctx, __gen_c.name, "UnresolveStep", nil, opts...); err != nil {
		return
	}
	if ierr := call.Finish(&reply, &err); ierr != nil {
		err = ierr
	}
	return
}

func (__gen_c *clientStubFortune) Signature(ctx _gen_context.T, opts ..._gen_ipc.CallOpt) (reply _gen_ipc.ServiceSignature, err error) {
	var call _gen_ipc.Call
	if call, err = __gen_c.client(ctx).StartCall(ctx, __gen_c.name, "Signature", nil, opts...); err != nil {
		return
	}
	if ierr := call.Finish(&reply, &err); ierr != nil {
		err = ierr
	}
	return
}

func (__gen_c *clientStubFortune) GetMethodTags(ctx _gen_context.T, method string, opts ..._gen_ipc.CallOpt) (reply []interface{}, err error) {
	var call _gen_ipc.Call
	if call, err = __gen_c.client(ctx).StartCall(ctx, __gen_c.name, "GetMethodTags", []interface{}{method}, opts...); err != nil {
		return
	}
	if ierr := call.Finish(&reply, &err); ierr != nil {
		err = ierr
	}
	return
}

// ServerStubFortune wraps a server that implements
// FortuneService and provides an object that satisfies
// the requirements of veyron2/ipc.ReflectInvoker.
type ServerStubFortune struct {
	service FortuneService
}

func (__gen_s *ServerStubFortune) GetMethodTags(call _gen_ipc.ServerCall, method string) ([]interface{}, error) {
	// TODO(bprosnitz) GetMethodTags() will be replaces with Signature().
	// Note: This exhibits some weird behavior like returning a nil error if the method isn't found.
	// This will change when it is replaced with Signature().
	switch method {
	case "Get":
		return []interface{}{security.Label(2)}, nil
	case "Add":
		return []interface{}{security.Label(4)}, nil
	default:
		return nil, nil
	}
}

func (__gen_s *ServerStubFortune) Signature(call _gen_ipc.ServerCall) (_gen_ipc.ServiceSignature, error) {
	result := _gen_ipc.ServiceSignature{Methods: make(map[string]_gen_ipc.MethodSignature)}
	result.Methods["Add"] = _gen_ipc.MethodSignature{
		InArgs: []_gen_ipc.MethodArgument{
			{Name: "Fortune", Type: 3},
		},
		OutArgs: []_gen_ipc.MethodArgument{
			{Name: "", Type: 65},
		},
	}
	result.Methods["Get"] = _gen_ipc.MethodSignature{
		InArgs: []_gen_ipc.MethodArgument{},
		OutArgs: []_gen_ipc.MethodArgument{
			{Name: "Fortune", Type: 3},
			{Name: "Err", Type: 65},
		},
	}

	result.TypeDefs = []_gen_vdlutil.Any{
		_gen_wiretype.NamedPrimitiveType{Type: 0x1, Name: "error", Tags: []string(nil)}}

	return result, nil
}

func (__gen_s *ServerStubFortune) UnresolveStep(call _gen_ipc.ServerCall) (reply []string, err error) {
	if unresolver, ok := __gen_s.service.(_gen_ipc.Unresolver); ok {
		return unresolver.UnresolveStep(call)
	}
	if call.Server() == nil {
		return
	}
	var published []string
	if published, err = call.Server().Published(); err != nil || published == nil {
		return
	}
	reply = make([]string, len(published))
	for i, p := range published {
		reply[i] = _gen_naming.Join(p, call.Name())
	}
	return
}

func (__gen_s *ServerStubFortune) Get(call _gen_ipc.ServerCall) (reply string, err error) {
	reply, err = __gen_s.service.Get(call)
	return
}

func (__gen_s *ServerStubFortune) Add(call _gen_ipc.ServerCall, Fortune string) (err error) {
	err = __gen_s.service.Add(call, Fortune)
	return
}
<commit_msg>test/fortune: Update generated vdl.go files to match go/vcl/6426.<commit_after>// This file was auto-generated by the veyron vdl tool.
// Source: fortune.vdl

package fortune

import (
	"veyron.io/veyron/veyron2/security"

	// The non-user imports are prefixed with "_gen_" to prevent collisions.
	_gen_veyron2 "veyron.io/veyron/veyron2"
	_gen_context "veyron.io/veyron/veyron2/context"
	_gen_ipc "veyron.io/veyron/veyron2/ipc"
	_gen_naming "veyron.io/veyron/veyron2/naming"
	_gen_vdlutil "veyron.io/veyron/veyron2/vdl/vdlutil"
	_gen_wiretype "veyron.io/veyron/veyron2/wiretype"
)

// TODO(toddw): Remove this line once the new signature support is done.
// It corrects a bug where _gen_wiretype is unused in VDL pacakges where only
// bootstrap types are used on interfaces.
const _ = _gen_wiretype.TypeIDInvalid

// Fortune allows clients to Get and Add fortune strings.
// Fortune is the interface the client binds and uses.
// Fortune_ExcludingUniversal is the interface without internal framework-added methods
// to enable embedding without method collisions.  Not to be used directly by clients.
type Fortune_ExcludingUniversal interface {
	// Get returns a random fortune.
	Get(ctx _gen_context.T, opts ..._gen_ipc.CallOpt) (reply string, err error)
	// Add stores a fortune in the set used by Get.
	Add(ctx _gen_context.T, Fortune string, opts ..._gen_ipc.CallOpt) (err error)
}
type Fortune interface {
	_gen_ipc.UniversalServiceMethods
	Fortune_ExcludingUniversal
}

// FortuneService is the interface the server implements.
type FortuneService interface {

	// Get returns a random fortune.
	Get(context _gen_ipc.ServerContext) (reply string, err error)
	// Add stores a fortune in the set used by Get.
	Add(context _gen_ipc.ServerContext, Fortune string) (err error)
}

// BindFortune returns the client stub implementing the Fortune
// interface.
//
// If no _gen_ipc.Client is specified, the default _gen_ipc.Client in the
// global Runtime is used.
func BindFortune(name string, opts ..._gen_ipc.BindOpt) (Fortune, error) {
	var client _gen_ipc.Client
	switch len(opts) {
	case 0:
		// Do nothing.
	case 1:
		if clientOpt, ok := opts[0].(_gen_ipc.Client); opts[0] == nil || ok {
			client = clientOpt
		} else {
			return nil, _gen_vdlutil.ErrUnrecognizedOption
		}
	default:
		return nil, _gen_vdlutil.ErrTooManyOptionsToBind
	}
	stub := &clientStubFortune{defaultClient: client, name: name}

	return stub, nil
}

// NewServerFortune creates a new server stub.
//
// It takes a regular server implementing the FortuneService
// interface, and returns a new server stub.
func NewServerFortune(server FortuneService) interface{} {
	stub := &ServerStubFortune{
		service: server,
	}
	var gs _gen_ipc.GlobState
	var self interface{} = stub
	// VAllGlobber is implemented by the server object, which is wrapped in
	// a VDL generated server stub.
	if x, ok := self.(_gen_ipc.VAllGlobber); ok {
		gs.VAllGlobber = x
	}
	// VAllGlobber is implemented by the server object without using a VDL
	// generated stub.
	if x, ok := server.(_gen_ipc.VAllGlobber); ok {
		gs.VAllGlobber = x
	}
	// VChildrenGlobber is implemented in the server object.
	if x, ok := server.(_gen_ipc.VChildrenGlobber); ok {
		gs.VChildrenGlobber = x
	}
	stub.gs = &gs
	return stub
}

// clientStubFortune implements Fortune.
type clientStubFortune struct {
	defaultClient _gen_ipc.Client
	name          string
}

func (__gen_c *clientStubFortune) client(ctx _gen_context.T) _gen_ipc.Client {
	if __gen_c.defaultClient != nil {
		return __gen_c.defaultClient
	}
	return _gen_veyron2.RuntimeFromContext(ctx).Client()
}

func (__gen_c *clientStubFortune) Get(ctx _gen_context.T, opts ..._gen_ipc.CallOpt) (reply string, err error) {
	var call _gen_ipc.Call
	if call, err = __gen_c.client(ctx).StartCall(ctx, __gen_c.name, "Get", nil, opts...); err != nil {
		return
	}
	if ierr := call.Finish(&reply, &err); ierr != nil {
		err = ierr
	}
	return
}

func (__gen_c *clientStubFortune) Add(ctx _gen_context.T, Fortune string, opts ..._gen_ipc.CallOpt) (err error) {
	var call _gen_ipc.Call
	if call, err = __gen_c.client(ctx).StartCall(ctx, __gen_c.name, "Add", []interface{}{Fortune}, opts...); err != nil {
		return
	}
	if ierr := call.Finish(&err); ierr != nil {
		err = ierr
	}
	return
}

func (__gen_c *clientStubFortune) UnresolveStep(ctx _gen_context.T, opts ..._gen_ipc.CallOpt) (reply []string, err error) {
	var call _gen_ipc.Call
	if call, err = __gen_c.client(ctx).StartCall(ctx, __gen_c.name, "UnresolveStep", nil, opts...); err != nil {
		return
	}
	if ierr := call.Finish(&reply, &err); ierr != nil {
		err = ierr
	}
	return
}

func (__gen_c *clientStubFortune) Signature(ctx _gen_context.T, opts ..._gen_ipc.CallOpt) (reply _gen_ipc.ServiceSignature, err error) {
	var call _gen_ipc.Call
	if call, err = __gen_c.client(ctx).StartCall(ctx, __gen_c.name, "Signature", nil, opts...); err != nil {
		return
	}
	if ierr := call.Finish(&reply, &err); ierr != nil {
		err = ierr
	}
	return
}

func (__gen_c *clientStubFortune) GetMethodTags(ctx _gen_context.T, method string, opts ..._gen_ipc.CallOpt) (reply []interface{}, err error) {
	var call _gen_ipc.Call
	if call, err = __gen_c.client(ctx).StartCall(ctx, __gen_c.name, "GetMethodTags", []interface{}{method}, opts...); err != nil {
		return
	}
	if ierr := call.Finish(&reply, &err); ierr != nil {
		err = ierr
	}
	return
}

// ServerStubFortune wraps a server that implements
// FortuneService and provides an object that satisfies
// the requirements of veyron2/ipc.ReflectInvoker.
type ServerStubFortune struct {
	service FortuneService
	gs      *_gen_ipc.GlobState
}

func (__gen_s *ServerStubFortune) GetMethodTags(call _gen_ipc.ServerCall, method string) ([]interface{}, error) {
	// TODO(bprosnitz) GetMethodTags() will be replaces with Signature().
	// Note: This exhibits some weird behavior like returning a nil error if the method isn't found.
	// This will change when it is replaced with Signature().
	switch method {
	case "Get":
		return []interface{}{security.Label(2)}, nil
	case "Add":
		return []interface{}{security.Label(4)}, nil
	default:
		return nil, nil
	}
}

func (__gen_s *ServerStubFortune) Signature(call _gen_ipc.ServerCall) (_gen_ipc.ServiceSignature, error) {
	result := _gen_ipc.ServiceSignature{Methods: make(map[string]_gen_ipc.MethodSignature)}
	result.Methods["Add"] = _gen_ipc.MethodSignature{
		InArgs: []_gen_ipc.MethodArgument{
			{Name: "Fortune", Type: 3},
		},
		OutArgs: []_gen_ipc.MethodArgument{
			{Name: "", Type: 65},
		},
	}
	result.Methods["Get"] = _gen_ipc.MethodSignature{
		InArgs: []_gen_ipc.MethodArgument{},
		OutArgs: []_gen_ipc.MethodArgument{
			{Name: "Fortune", Type: 3},
			{Name: "Err", Type: 65},
		},
	}

	result.TypeDefs = []_gen_vdlutil.Any{
		_gen_wiretype.NamedPrimitiveType{Type: 0x1, Name: "error", Tags: []string(nil)}}

	return result, nil
}

func (__gen_s *ServerStubFortune) UnresolveStep(call _gen_ipc.ServerCall) (reply []string, err error) {
	if unresolver, ok := __gen_s.service.(_gen_ipc.Unresolver); ok {
		return unresolver.UnresolveStep(call)
	}
	if call.Server() == nil {
		return
	}
	var published []string
	if published, err = call.Server().Published(); err != nil || published == nil {
		return
	}
	reply = make([]string, len(published))
	for i, p := range published {
		reply[i] = _gen_naming.Join(p, call.Name())
	}
	return
}

func (__gen_s *ServerStubFortune) VGlob() *_gen_ipc.GlobState {
	return __gen_s.gs
}

func (__gen_s *ServerStubFortune) Get(call _gen_ipc.ServerCall) (reply string, err error) {
	reply, err = __gen_s.service.Get(call)
	return
}

func (__gen_s *ServerStubFortune) Add(call _gen_ipc.ServerCall, Fortune string) (err error) {
	err = __gen_s.service.Add(call, Fortune)
	return
}
<|endoftext|>


<commit_before>package main

import (
    "log"
    "net"
    "time"
    "sync"
    "strings"
    "container/list"
    "huabot-sched/db"
)

type Sched struct {
    TotalWorkerCount int
    timer            *time.Timer
    grabQueue        *list.List
    jobQueue         *list.List
    entryPoint       string
    JobLocker        *sync.Mutex
    Funcs            map[string]*FuncStat
}

type FuncStat struct {
    TotalWorker int
    TotalJob    int
    DoingJob    int
}

func (stat *FuncStat) IncrWorker() int {
    stat.TotalWorker += 1
    return stat.TotalWorker
}

func (stat *FuncStat) DecrWorker() int {
    stat.TotalWorker -= 1
    return stat.TotalWorker
}

func (stat *FuncStat) IncrJob() int {
    stat.TotalJob += 1
    return stat.TotalJob
}

func (stat *FuncStat) DecrJob() int {
    stat.TotalJob -= 1
    return stat.TotalJob
}

func (stat *FuncStat) IncrDoing() int {
    stat.DoingJob += 1
    return stat.DoingJob
}

func (stat *FuncStat) DecrDoing() int {
    stat.DoingJob -= 1
    return stat.DoingJob
}

func NewSched(entryPoint string) *Sched {
    sched = new(Sched)
    sched.TotalWorkerCount = 0
    sched.timer = time.NewTimer(1 * time.Hour)
    sched.grabQueue = list.New()
    sched.jobQueue = list.New()
    sched.entryPoint = entryPoint
    sched.JobLocker = new(sync.Mutex)
    sched.Funcs = make(map[string]*FuncStat)
    return sched
}

func (sched *Sched) Serve() {
    parts := strings.SplitN(sched.entryPoint, "://", 2)
    if parts[0] == "unix" {
        sockCheck(parts[1])
    }
    sched.checkJobQueue()
    go sched.handle()
    listen, err := net.Listen(parts[0], parts[1])
    if err != nil {
        log.Fatal(err)
    }
    defer listen.Close()
    log.Printf("huabot-sched started on %s\n", sched.entryPoint)
    for {
        conn, err := listen.Accept()
        if err != nil {
            log.Fatal(err)
        }
        sched.HandleConnection(conn)
    }
}

func (sched *Sched) Notify() {
    sched.timer.Reset(time.Millisecond)
}

func (sched *Sched) DieWorker(worker *Worker) {
    defer sched.Notify()
    sched.TotalWorkerCount -= 1
    log.Printf("Total worker: %d\n", sched.TotalWorkerCount)
    sched.removeGrabQueue(worker)
    worker.Close()
}

func (sched *Sched) HandleConnection(conn net.Conn) {
    worker := NewWorker(sched, Conn{Conn: conn})
    sched.TotalWorkerCount += 1
    log.Printf("Total worker: %d\n", sched.TotalWorkerCount)
    go worker.Handle()
}

func (sched *Sched) Done(jobId int64) {
    defer sched.Notify()
    defer sched.JobLocker.Unlock()
    sched.JobLocker.Lock()
    removeListJob(sched.jobQueue, jobId)
    job, err := db.GetJob(jobId)
    if err == nil {
        job.Delete()
        sched.RemoveJob(job)
        sched.RemoveDoing(job)
    }
    return
}

func (sched *Sched) isDoJob(job db.Job) bool {
    now := time.Now()
    current := int64(now.Unix())
    ret := false
    for e := sched.jobQueue.Front(); e != nil; e = e.Next() {
        chk := e.Value.(db.Job)
        runAt := chk.RunAt
        if runAt < chk.SchedAt {
            runAt = chk.SchedAt
        }
        if chk.Timeout > 0 && runAt + chk.Timeout < current {
            newJob, _ := db.GetJob(chk.Id)
            if newJob.Status == "doing" {
                newJob.Status = "ready"
                newJob.Save()
                sched.RemoveDoing(newJob)
            }
            sched.jobQueue.Remove(e)
            continue
        }
        if chk.Id == job.Id {
            old := e.Value.(db.Job)
            runAt := old.RunAt
            if runAt < old.SchedAt {
                runAt = old.SchedAt
            }
            if old.Timeout > 0 && runAt + old.Timeout < current {
                ret = false
            } else {
                ret = true
            }
        }
    }
    return ret
}

func (sched *Sched) SubmitJob(worker *Worker, job db.Job) {
    defer sched.JobLocker.Unlock()
    sched.JobLocker.Lock()
    if job.Name == "" {
        job.Delete()
        return
    }
    if sched.isDoJob(job) {
        return
    }
    if !worker.alive {
        return
    }
    if err := worker.HandleDo(job); err != nil {
        worker.alive = false
        sched.DieWorker(worker)
        return
    }
    now := time.Now()
    current := int64(now.Unix())
    job.Status = "doing"
    job.RunAt = current
    job.Save()
    sched.AddDoing(job)
    sched.jobQueue.PushBack(job)
    sched.removeGrabQueue(worker)
}

func (sched *Sched) handle() {
    var current time.Time
    var timestamp int64
    var schedJob db.Job
    var isFirst bool
    for {
        if sched.grabQueue.Len() == 0 {
            sched.timer.Reset(time.Minute)
            current =<-sched.timer.C
            continue
        }

        isFirst = true
        for Func, stat := range sched.Funcs {
            if stat.TotalWorker == 0 || (stat.TotalJob > 0 && stat.DoingJob < stat.TotalJob) {
                continue
            }
            jobs, err := db.RangeSchedJob(Func, "ready", 0, 0)
            if err != nil || len(jobs) == 0 {
                stat.TotalJob = stat.DoingJob
                continue
            }

            if isFirst {
                schedJob = jobs[0]
                isFirst = false
                continue
            }

            if schedJob.SchedAt > jobs[0].SchedAt {
                schedJob = jobs[0]
            }
        }
        if isFirst {
            sched.timer.Reset(time.Minute)
            current =<-sched.timer.C
            continue
        }

        timestamp = int64(time.Now().Unix())

        if schedJob.SchedAt > timestamp {
            sched.timer.Reset(time.Second * time.Duration(schedJob.SchedAt - timestamp))
            current =<-sched.timer.C
            timestamp = int64(current.Unix())
            if schedJob.SchedAt > timestamp {
                continue
            }
        }

        isSubmited := false
        for e := sched.grabQueue.Front(); e != nil; e = e.Next() {
            worker := e.Value.(*Worker)
            for _, Func := range worker.Funcs {
                if schedJob.Func == Func {
                    sched.SubmitJob(worker, schedJob)
                    isSubmited = true
                    break
                }
            }
            if isSubmited {
                break
            }
        }

        if !isSubmited {
            sched.RemoveFunc(schedJob.Func)
        }
    }
}

func (sched *Sched) Fail(jobId int64) {
    defer sched.Notify()
    defer sched.JobLocker.Unlock()
    sched.JobLocker.Lock()
    removeListJob(sched.jobQueue, jobId)
    job, _ := db.GetJob(jobId)
    job.Status = "ready"
    job.Save()
    return
}

func (sched *Sched) AddFunc(Func string) {
    stat, ok := sched.Funcs[Func]
    if !ok {
        stat = new(FuncStat)
        sched.Funcs[Func] = stat
    }
    stat.IncrWorker()
}

func (sched *Sched) RemoveFunc(Func string) {
    stat, ok := sched.Funcs[Func]
    if ok {
        stat.DecrWorker()
    }
}

func (sched *Sched) AddJob(job db.Job) {
    stat, ok := sched.Funcs[job.Func]
    if !ok {
        stat = new(FuncStat)
        sched.Funcs[job.Func] = stat
    }
    stat.IncrJob()
}

func (sched *Sched) RemoveJob(job db.Job) {
    stat, ok := sched.Funcs[job.Func]
    if ok {
        stat.DecrJob()
    }
}

func (sched *Sched) AddDoing(job db.Job) {
    stat, ok := sched.Funcs[job.Func]
    if !ok {
        stat = new(FuncStat)
        sched.Funcs[job.Func] = stat
    }
    stat.IncrDoing()
}

func (sched *Sched) RemoveDoing(job db.Job) {
    stat, ok := sched.Funcs[job.Func]
    if ok {
        stat.DecrDoing()
    }
}

func (sched *Sched) SchedLater(jobId int64, delay int64) {
    defer sched.Notify()
    defer sched.JobLocker.Unlock()
    sched.JobLocker.Lock()
    removeListJob(sched.jobQueue, jobId)
    job, _ := db.GetJob(jobId)
    job.Status = "ready"
    var now = time.Now()
    job.SchedAt = int64(now.Unix()) + delay
    job.Save()
    sched.RemoveDoing(job)
    return
}

func (sched *Sched) removeGrabQueue(worker *Worker) {
    for e := sched.grabQueue.Front(); e != nil; e = e.Next() {
        if e.Value.(*Worker) == worker {
            sched.grabQueue.Remove(e)
        }
    }
}

func (sched *Sched) checkJobQueue() {
    start := 0
    limit := 20
    total, _ := db.CountJob()
    updateQueue := make([]db.Job, 0)
    removeQueue := make([]db.Job, 0)
    var now = time.Now()
    current := int64(now.Unix())

    for start = 0; start < int(total); start += limit {
        jobs, _ := db.RangeJob(start, start + limit)
        for _, job := range jobs {
            if job.Name == "" {
                removeQueue = append(removeQueue, job)
                continue
            }
            sched.AddJob(job)
            if job.Status != "doing" {
                continue
            }
            runAt := job.RunAt
            if runAt < job.SchedAt {
                runAt = job.SchedAt
            }
            if runAt + job.Timeout < current {
                updateQueue = append(updateQueue, job)
            } else {
                sched.jobQueue.PushBack(job)
                sched.AddDoing(job)
            }
        }
    }

    for _, job := range updateQueue {
        job.Status = "ready"
        job.Save()
    }

    for _, job := range removeQueue {
        job.Delete()
    }
}

func (sched *Sched) Close() {
}
<commit_msg>Add jsonable FuncStat<commit_after>package main

import (
    "log"
    "net"
    "time"
    "sync"
    "strings"
    "container/list"
    "huabot-sched/db"
)

type Sched struct {
    TotalWorkerCount int
    timer            *time.Timer
    grabQueue        *list.List
    jobQueue         *list.List
    entryPoint       string
    JobLocker        *sync.Mutex
    Funcs            map[string]*FuncStat
}

type FuncStat struct {
    TotalWorker int `json:"worker_count"`
    TotalJob    int `json:"job_count"`
    DoingJob    int `json:"doing"`
}

func (stat *FuncStat) IncrWorker() int {
    stat.TotalWorker += 1
    return stat.TotalWorker
}

func (stat *FuncStat) DecrWorker() int {
    stat.TotalWorker -= 1
    return stat.TotalWorker
}

func (stat *FuncStat) IncrJob() int {
    stat.TotalJob += 1
    return stat.TotalJob
}

func (stat *FuncStat) DecrJob() int {
    stat.TotalJob -= 1
    return stat.TotalJob
}

func (stat *FuncStat) IncrDoing() int {
    stat.DoingJob += 1
    return stat.DoingJob
}

func (stat *FuncStat) DecrDoing() int {
    stat.DoingJob -= 1
    return stat.DoingJob
}

func NewSched(entryPoint string) *Sched {
    sched = new(Sched)
    sched.TotalWorkerCount = 0
    sched.timer = time.NewTimer(1 * time.Hour)
    sched.grabQueue = list.New()
    sched.jobQueue = list.New()
    sched.entryPoint = entryPoint
    sched.JobLocker = new(sync.Mutex)
    sched.Funcs = make(map[string]*FuncStat)
    return sched
}

func (sched *Sched) Serve() {
    parts := strings.SplitN(sched.entryPoint, "://", 2)
    if parts[0] == "unix" {
        sockCheck(parts[1])
    }
    sched.checkJobQueue()
    go sched.handle()
    listen, err := net.Listen(parts[0], parts[1])
    if err != nil {
        log.Fatal(err)
    }
    defer listen.Close()
    log.Printf("huabot-sched started on %s\n", sched.entryPoint)
    for {
        conn, err := listen.Accept()
        if err != nil {
            log.Fatal(err)
        }
        sched.HandleConnection(conn)
    }
}

func (sched *Sched) Notify() {
    sched.timer.Reset(time.Millisecond)
}

func (sched *Sched) DieWorker(worker *Worker) {
    defer sched.Notify()
    sched.TotalWorkerCount -= 1
    log.Printf("Total worker: %d\n", sched.TotalWorkerCount)
    sched.removeGrabQueue(worker)
    worker.Close()
}

func (sched *Sched) HandleConnection(conn net.Conn) {
    worker := NewWorker(sched, Conn{Conn: conn})
    sched.TotalWorkerCount += 1
    log.Printf("Total worker: %d\n", sched.TotalWorkerCount)
    go worker.Handle()
}

func (sched *Sched) Done(jobId int64) {
    defer sched.Notify()
    defer sched.JobLocker.Unlock()
    sched.JobLocker.Lock()
    removeListJob(sched.jobQueue, jobId)
    job, err := db.GetJob(jobId)
    if err == nil {
        job.Delete()
        sched.RemoveJob(job)
        sched.RemoveDoing(job)
    }
    return
}

func (sched *Sched) isDoJob(job db.Job) bool {
    now := time.Now()
    current := int64(now.Unix())
    ret := false
    for e := sched.jobQueue.Front(); e != nil; e = e.Next() {
        chk := e.Value.(db.Job)
        runAt := chk.RunAt
        if runAt < chk.SchedAt {
            runAt = chk.SchedAt
        }
        if chk.Timeout > 0 && runAt + chk.Timeout < current {
            newJob, _ := db.GetJob(chk.Id)
            if newJob.Status == "doing" {
                newJob.Status = "ready"
                newJob.Save()
                sched.RemoveDoing(newJob)
            }
            sched.jobQueue.Remove(e)
            continue
        }
        if chk.Id == job.Id {
            old := e.Value.(db.Job)
            runAt := old.RunAt
            if runAt < old.SchedAt {
                runAt = old.SchedAt
            }
            if old.Timeout > 0 && runAt + old.Timeout < current {
                ret = false
            } else {
                ret = true
            }
        }
    }
    return ret
}

func (sched *Sched) SubmitJob(worker *Worker, job db.Job) {
    defer sched.JobLocker.Unlock()
    sched.JobLocker.Lock()
    if job.Name == "" {
        job.Delete()
        return
    }
    if sched.isDoJob(job) {
        return
    }
    if !worker.alive {
        return
    }
    if err := worker.HandleDo(job); err != nil {
        worker.alive = false
        sched.DieWorker(worker)
        return
    }
    now := time.Now()
    current := int64(now.Unix())
    job.Status = "doing"
    job.RunAt = current
    job.Save()
    sched.AddDoing(job)
    sched.jobQueue.PushBack(job)
    sched.removeGrabQueue(worker)
}

func (sched *Sched) handle() {
    var current time.Time
    var timestamp int64
    var schedJob db.Job
    var isFirst bool
    for {
        if sched.grabQueue.Len() == 0 {
            sched.timer.Reset(time.Minute)
            current =<-sched.timer.C
            continue
        }

        isFirst = true
        for Func, stat := range sched.Funcs {
            if stat.TotalWorker == 0 || (stat.TotalJob > 0 && stat.DoingJob < stat.TotalJob) {
                continue
            }
            jobs, err := db.RangeSchedJob(Func, "ready", 0, 0)
            if err != nil || len(jobs) == 0 {
                stat.TotalJob = stat.DoingJob
                continue
            }

            if isFirst {
                schedJob = jobs[0]
                isFirst = false
                continue
            }

            if schedJob.SchedAt > jobs[0].SchedAt {
                schedJob = jobs[0]
            }
        }
        if isFirst {
            sched.timer.Reset(time.Minute)
            current =<-sched.timer.C
            continue
        }

        timestamp = int64(time.Now().Unix())

        if schedJob.SchedAt > timestamp {
            sched.timer.Reset(time.Second * time.Duration(schedJob.SchedAt - timestamp))
            current =<-sched.timer.C
            timestamp = int64(current.Unix())
            if schedJob.SchedAt > timestamp {
                continue
            }
        }

        isSubmited := false
        for e := sched.grabQueue.Front(); e != nil; e = e.Next() {
            worker := e.Value.(*Worker)
            for _, Func := range worker.Funcs {
                if schedJob.Func == Func {
                    sched.SubmitJob(worker, schedJob)
                    isSubmited = true
                    break
                }
            }
            if isSubmited {
                break
            }
        }

        if !isSubmited {
            sched.RemoveFunc(schedJob.Func)
        }
    }
}

func (sched *Sched) Fail(jobId int64) {
    defer sched.Notify()
    defer sched.JobLocker.Unlock()
    sched.JobLocker.Lock()
    removeListJob(sched.jobQueue, jobId)
    job, _ := db.GetJob(jobId)
    job.Status = "ready"
    job.Save()
    return
}

func (sched *Sched) AddFunc(Func string) {
    stat, ok := sched.Funcs[Func]
    if !ok {
        stat = new(FuncStat)
        sched.Funcs[Func] = stat
    }
    stat.IncrWorker()
}

func (sched *Sched) RemoveFunc(Func string) {
    stat, ok := sched.Funcs[Func]
    if ok {
        stat.DecrWorker()
    }
}

func (sched *Sched) AddJob(job db.Job) {
    stat, ok := sched.Funcs[job.Func]
    if !ok {
        stat = new(FuncStat)
        sched.Funcs[job.Func] = stat
    }
    stat.IncrJob()
}

func (sched *Sched) RemoveJob(job db.Job) {
    stat, ok := sched.Funcs[job.Func]
    if ok {
        stat.DecrJob()
    }
}

func (sched *Sched) AddDoing(job db.Job) {
    stat, ok := sched.Funcs[job.Func]
    if !ok {
        stat = new(FuncStat)
        sched.Funcs[job.Func] = stat
    }
    stat.IncrDoing()
}

func (sched *Sched) RemoveDoing(job db.Job) {
    stat, ok := sched.Funcs[job.Func]
    if ok {
        stat.DecrDoing()
    }
}

func (sched *Sched) SchedLater(jobId int64, delay int64) {
    defer sched.Notify()
    defer sched.JobLocker.Unlock()
    sched.JobLocker.Lock()
    removeListJob(sched.jobQueue, jobId)
    job, _ := db.GetJob(jobId)
    job.Status = "ready"
    var now = time.Now()
    job.SchedAt = int64(now.Unix()) + delay
    job.Save()
    sched.RemoveDoing(job)
    return
}

func (sched *Sched) removeGrabQueue(worker *Worker) {
    for e := sched.grabQueue.Front(); e != nil; e = e.Next() {
        if e.Value.(*Worker) == worker {
            sched.grabQueue.Remove(e)
        }
    }
}

func (sched *Sched) checkJobQueue() {
    start := 0
    limit := 20
    total, _ := db.CountJob()
    updateQueue := make([]db.Job, 0)
    removeQueue := make([]db.Job, 0)
    var now = time.Now()
    current := int64(now.Unix())

    for start = 0; start < int(total); start += limit {
        jobs, _ := db.RangeJob(start, start + limit)
        for _, job := range jobs {
            if job.Name == "" {
                removeQueue = append(removeQueue, job)
                continue
            }
            sched.AddJob(job)
            if job.Status != "doing" {
                continue
            }
            runAt := job.RunAt
            if runAt < job.SchedAt {
                runAt = job.SchedAt
            }
            if runAt + job.Timeout < current {
                updateQueue = append(updateQueue, job)
            } else {
                sched.jobQueue.PushBack(job)
                sched.AddDoing(job)
            }
        }
    }

    for _, job := range updateQueue {
        job.Status = "ready"
        job.Save()
    }

    for _, job := range removeQueue {
        job.Delete()
    }
}

func (sched *Sched) Close() {
}
<|endoftext|>