<commit_before>package brooklyn.policy

import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicInteger

import org.slf4j.Logger
import org.slf4j.LoggerFactory

import brooklyn.entity.Entity
import brooklyn.entity.basic.EntityLocal
import brooklyn.entity.trait.Resizable
import brooklyn.entity.trait.Startable
import brooklyn.event.AttributeSensor
import brooklyn.event.SensorEvent
import brooklyn.event.SensorEventListener
import brooklyn.policy.basic.AbstractPolicy
import brooklyn.util.task.BasicTask

public class ResizerPolicy<T extends Number> extends AbstractPolicy implements SensorEventListener<T> {
    
    // TODO Currently only does one resize at a time.
    // Imagine the threshold is set to 100. If we ramp up workrate to 450, but the policy sees events for 101 then 450, 
    // the first event will cause it to provision a single new instance. After the several minutes that this takes, it 
    // will then concurrently provision up to the correct number of instances (in this case, 5).
    
    private static final Logger LOG = LoggerFactory.getLogger(ResizerPolicy.class)

    private AttributeSensor<T> source
    private Resizable resizable
    private boolean entityStartable = false
    private String[] metricName
    private T metricLowerBound
    private T metricUpperBound
    private int minSize
    private int maxSize = Integer.MAX_VALUE

    private final AtomicInteger desiredSize = new AtomicInteger(0)

    /** Lock held if we are in the process of resizing. */
    private final AtomicBoolean resizing = new AtomicBoolean(false)
    private final AtomicBoolean suspended = new AtomicBoolean(false)
    
    private Closure resizeAction = {
        try {
            LOG.info "policy resizer performing resizing..."
            int desire = desiredSize.get()
            resizable.resize(desire)
            while (desire != desiredSize.get()) {
                LOG.info "policy resizer performing re-resizing..."
                desire = desiredSize.get()
                resizable.resize(desire)
            }
            LOG.info "policy resizer resizing complete"
        } finally {
            resizing.set(false)
        }
    }


    /**
     * @param averagingSource - A sensor that averages a relevant metric across the attaching entity
     */
    public ResizerPolicy(AttributeSensor<T> averagingSource) {
        this.source = averagingSource
    }

    @Override
    public void setEntity(Entity entity) {
        super.setEntity(entity)
        assert entity instanceof Resizable
        this.resizable = entity
        if(entity instanceof Startable) {
            entityStartable = true
        }
        subscribe(entity, source, this)
    }

    public ResizerPolicy setMetricLowerBound(T val) {
        this.metricLowerBound = val
        this
    }

    public ResizerPolicy setMetricUpperBound(T val) {
        this.metricUpperBound = val
        this
    }

    public ResizerPolicy setMinSize(int val) {
        this.minSize = val
        this
    }

    public ResizerPolicy setMaxSize(int val) {
        this.maxSize = val
        this
    }
    
    @Override
    public void suspend() {
        suspended.set(true)
    }

    @Override
    public void resume() {
        suspended.set(false)
    }

    private void resize() {
        if (!suspended.get() && (!entityStartable || entity.getAttribute(Startable.SERVICE_UP))
                && resizing.compareAndSet(false, true)) {
            ((EntityLocal)entity).getManagementContext().getExecutionContext(entity).submit(new BasicTask(resizeAction))
        }
    }

    public void onEvent(SensorEvent<T> event) {
        T val = event.getValue()
        int currentSize = resizable.getCurrentSize()
        desiredSize.set(calculateDesiredSize(val))

        if (desiredSize.get() != currentSize) {
            LOG.debug "policy resizer resizing: metric={}, workrate={}, lowerBound={}, upperBound={}; currentSize={}, desiredSize={}, minSize={}, maxSize={}",
                    source, val, metricLowerBound, metricUpperBound, currentSize, desiredSize.get(), minSize, maxSize
            resize()
        } else {
            LOG.trace "policy resizer doing nothing: metric={}, workrate={}, lowerBound={}, upperBound={}; currentSize={}, minSize={}, maxSize={}",
                    source, val, metricLowerBound, metricUpperBound, currentSize, minSize, maxSize
        }
    }

    // TODO Could have throttling etc so don't repeatedly call grow; standard control theory stuff such as
    //      PID design (proportional-integral-derivative)
    // TODO Could show example of overriding this to do something smarter
    protected int calculateDesiredSize(T currentMetric) {
        int currentSize = resizable.getCurrentSize()
        int desiredSize
        if (0 < currentMetric - metricUpperBound) {
            desiredSize = currentSize+Math.ceil(currentSize * ((currentMetric - metricUpperBound) / metricUpperBound))// scale out
        } else if (0 < metricLowerBound - currentMetric) {
            desiredSize = currentSize-Math.ceil(currentSize * (Math.abs(currentMetric - metricLowerBound) / metricLowerBound)) // scale back<commit_msg>removed obsolete methods and switched to use accessor method<commit_after>package brooklyn.policy

import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicInteger

import org.slf4j.Logger
import org.slf4j.LoggerFactory

import brooklyn.entity.Entity
import brooklyn.entity.basic.EntityLocal
import brooklyn.entity.trait.Resizable
import brooklyn.entity.trait.Startable
import brooklyn.event.AttributeSensor
import brooklyn.event.SensorEvent
import brooklyn.event.SensorEventListener
import brooklyn.policy.basic.AbstractPolicy
import brooklyn.util.task.BasicTask

public class ResizerPolicy<T extends Number> extends AbstractPolicy implements SensorEventListener<T> {
    
    // TODO Currently only does one resize at a time.
    // Imagine the threshold is set to 100. If we ramp up workrate to 450, but the policy sees events for 101 then 450, 
    // the first event will cause it to provision a single new instance. After the several minutes that this takes, it 
    // will then concurrently provision up to the correct number of instances (in this case, 5).
    
    private static final Logger LOG = LoggerFactory.getLogger(ResizerPolicy.class)

    private AttributeSensor<T> source
    private Resizable resizable
    private boolean entityStartable = false
    private String[] metricName
    private T metricLowerBound
    private T metricUpperBound
    private int minSize
    private int maxSize = Integer.MAX_VALUE

    private final AtomicInteger desiredSize = new AtomicInteger(0)

    /** Lock held if we are in the process of resizing. */
    private final AtomicBoolean resizing = new AtomicBoolean(false)
    
    private Closure resizeAction = {
        try {
            LOG.info "policy resizer performing resizing..."
            int desire = desiredSize.get()
            resizable.resize(desire)
            while (desire != desiredSize.get()) {
                LOG.info "policy resizer performing re-resizing..."
                desire = desiredSize.get()
                resizable.resize(desire)
            }
            LOG.info "policy resizer resizing complete"
        } finally {
            resizing.set(false)
        }
    }


    /**
     * @param averagingSource - A sensor that averages a relevant metric across the attaching entity
     */
    public ResizerPolicy(AttributeSensor<T> averagingSource) {
        this.source = averagingSource
    }

    @Override
    public void setEntity(Entity entity) {
        super.setEntity(entity)
        assert entity instanceof Resizable
        this.resizable = entity
        if(entity instanceof Startable) {
            entityStartable = true
        }
        subscribe(entity, source, this)
    }

    public ResizerPolicy setMetricLowerBound(T val) {
        this.metricLowerBound = val
        this
    }

    public ResizerPolicy setMetricUpperBound(T val) {
        this.metricUpperBound = val
        this
    }

    public ResizerPolicy setMinSize(int val) {
        this.minSize = val
        this
    }

    public ResizerPolicy setMaxSize(int val) {
        this.maxSize = val
        this
    }
    

    private void resize() {
        if (!isSuspended() && (!entityStartable || entity.getAttribute(Startable.SERVICE_UP))
                && resizing.compareAndSet(false, true)) {
            ((EntityLocal)entity).getManagementContext().getExecutionContext(entity).submit(new BasicTask(resizeAction))
        }
    }

    public void onEvent(SensorEvent<T> event) {
        T val = event.getValue()
        int currentSize = resizable.getCurrentSize()
        desiredSize.set(calculateDesiredSize(val))

        if (desiredSize.get() != currentSize) {
            LOG.debug "policy resizer resizing: metric={}, workrate={}, lowerBound={}, upperBound={}; currentSize={}, desiredSize={}, minSize={}, maxSize={}",
                    source, val, metricLowerBound, metricUpperBound, currentSize, desiredSize.get(), minSize, maxSize
            resize()
        } else {
            LOG.trace "policy resizer doing nothing: metric={}, workrate={}, lowerBound={}, upperBound={}; currentSize={}, minSize={}, maxSize={}",
                    source, val, metricLowerBound, metricUpperBound, currentSize, minSize, maxSize
        }
    }

    // TODO Could have throttling etc so don't repeatedly call grow; standard control theory stuff such as
    //      PID design (proportional-integral-derivative)
    // TODO Could show example of overriding this to do something smarter
    protected int calculateDesiredSize(T currentMetric) {
        int currentSize = resizable.getCurrentSize()
        int desiredSize
        if (0 < currentMetric - metricUpperBound) {
            desiredSize = currentSize+Math.ceil(currentSize * ((currentMetric - metricUpperBound) / metricUpperBound))// scale out
        } else if (0 < metricLowerBound - currentMetric) {
            desiredSize = currentSize-Math.ceil(currentSize * (Math.abs(currentMetric - metricLowerBound) / metricLowerBound)) // scale back
{'fraction_non_alphanumeric': 0.08256614012985754, 'fraction_numerical': 0.003488710146332009, 'mean_word_length': 2.8053097345132745, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 13, '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': '6342496', 'n_tokens_mistral': 2724, 'n_tokens_neox': 2635, 'n_words': 793}