All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opensearch.ml.common.controller.MLRateLimiter Maven / Gradle / Ivy

The newest version!
/*
 * Copyright OpenSearch Contributors
 * SPDX-License-Identifier: Apache-2.0
 */

package org.opensearch.ml.common.controller;

import static org.opensearch.core.xcontent.XContentParserUtils.ensureExpectedToken;

import java.io.IOException;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

import org.opensearch.OpenSearchParseException;
import org.opensearch.core.common.io.stream.StreamInput;
import org.opensearch.core.common.io.stream.StreamOutput;
import org.opensearch.core.common.io.stream.Writeable;
import org.opensearch.core.xcontent.ToXContent;
import org.opensearch.core.xcontent.ToXContentObject;
import org.opensearch.core.xcontent.XContentBuilder;
import org.opensearch.core.xcontent.XContentParser;

import lombok.Builder;
import lombok.Getter;
import lombok.Setter;

@Setter
@Getter
public class MLRateLimiter implements ToXContentObject, Writeable {
    public static final String LIMIT_FIELD = "limit";
    public static final String UNIT_FIELD = "unit";

    private String limit;
    private TimeUnit unit;

    @Builder(toBuilder = true)
    public MLRateLimiter(String limit, TimeUnit unit) {
        this.limit = limit;
        this.unit = unit;
    }

    public static MLRateLimiter parse(XContentParser parser) throws IOException {
        String limit = null;
        TimeUnit unit = null;

        ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.currentToken(), parser);
        while (parser.nextToken() != XContentParser.Token.END_OBJECT) {
            String fieldName = parser.currentName();
            parser.nextToken();

            switch (fieldName) {
                case LIMIT_FIELD:
                    limit = parser.text();
                    try {
                        double limitNumber = Double.parseDouble(limit);
                        if (limitNumber < 0) {
                            throw new OpenSearchParseException("Limit field must be a positive number.");
                        }
                    } catch (NumberFormatException e) {
                        throw new OpenSearchParseException("Limit field must be a positive number.");
                    }
                    break;
                case UNIT_FIELD:
                    unit = TimeUnit.valueOf(parser.text());
                    break;
                default:
                    parser.skipChildren();
                    break;
            }
        }
        return new MLRateLimiter(limit, unit);
    }

    public MLRateLimiter(StreamInput in) throws IOException {
        this.limit = in.readOptionalString();
        if (in.readBoolean()) {
            this.unit = in.readEnum(TimeUnit.class);
        }
    }

    @Override
    public void writeTo(StreamOutput out) throws IOException {
        out.writeOptionalString(limit);
        if (unit != null) {
            out.writeBoolean(true);
            out.writeEnum(unit);
        } else {
            out.writeBoolean(false);
        }
    }

    @Override
    public XContentBuilder toXContent(XContentBuilder builder, ToXContent.Params params) throws IOException {
        builder.startObject();
        if (limit != null) {
            builder.field(LIMIT_FIELD, limit);
        }
        if (unit != null) {
            builder.field(UNIT_FIELD, unit);
        }
        builder.endObject();
        return builder;
    }

    public void update(MLRateLimiter updateContent) {
        if (updateContent.getLimit() != null) {
            this.limit = updateContent.getLimit();
        }
        if (updateContent.getUnit() != null) {
            this.unit = updateContent.getUnit();
        }
    }

    public static MLRateLimiter update(MLRateLimiter rateLimiter, MLRateLimiter updateContent) {
        if (rateLimiter == null) {
            return updateContent;
        } else {
            rateLimiter.update(updateContent);
            return rateLimiter;
        }
    }

    /**
     * Checks the validity of this incoming update before performing an update
     * operation.
     * A valid update indicates the corresponding index will be updated with the
     * current MLRateLimiter config and the update content
     *
     * @param rateLimiter   The existing rate limiter.
     * @param updateContent The update content.
     * @return true if the update is valid, false otherwise.
     */
    public static boolean updateValidityPreCheck(MLRateLimiter rateLimiter, MLRateLimiter updateContent) {
        if (updateContent == null) {
            return false;
        } else if (rateLimiter == null) {
            return true;
        } else if (updateContent.isEmpty()) {
            return false;
        } else
            return (!Objects.equals(updateContent.getLimit(), rateLimiter.getLimit()) && updateContent.getLimit() != null)
                || (!Objects.equals(updateContent.getUnit(), rateLimiter.getUnit()) && updateContent.getUnit() != null);
    }

    /**
     * Checks if we need to deploy this update into ML Cache (if model is deployed)
     * after performing this update operation.
     *
     * @param rateLimiter   The existing rate limiter.
     * @param updateContent The update content.
     * @return true if the update is valid, false otherwise.
     */
    public static boolean isDeployRequiredAfterUpdate(MLRateLimiter rateLimiter, MLRateLimiter updateContent) {
        if (!updateValidityPreCheck(rateLimiter, updateContent)) {
            return false;
        } else {
            return updateContent.isValid()
                || (rateLimiter.getUnit() != null && updateContent.getLimit() != null)
                || (rateLimiter.getLimit() != null && updateContent.getUnit() != null);
        }
    }

    public boolean isValid() {
        return (this.unit != null && this.limit != null);
    }

    public boolean isEmpty() {
        return (this.unit == null && this.limit == null);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy