oracle.kv.impl.api.table.TableLimits Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of oracle-nosql-server Show documentation
Show all versions of oracle-nosql-server Show documentation
NoSQL Database Server - supplies build and runtime support for the server (store) side of the Oracle NoSQL Database.
/*-
* Copyright (C) 2011, 2018 Oracle and/or its affiliates. All rights reserved.
*
* This file was distributed by Oracle as part of a version of Oracle NoSQL
* Database made available at:
*
* http://www.oracle.com/technetwork/database/database-technologies/nosqldb/downloads/index.html
*
* Please see the LICENSE file included in the top-level directory of the
* appropriate version of Oracle NoSQL Database for a copy of the license and
* additional information.
*/
package oracle.kv.impl.api.table;
import java.io.IOException;
import java.io.Serializable;
import oracle.kv.KVVersion;
import org.codehaus.jackson.node.ArrayNode;
import org.codehaus.jackson.node.ObjectNode;
/**
* Container for table limits.
*
*/
public class TableLimits implements Serializable {
private static final long serialVersionUID = 1L;
/* KV Version where limits was introduced */
public static final KVVersion TABLE_LIMITS_VERSION = KVVersion.R18_1;
/* Initial implementation */
private static final int V1 = 1;
private static final int CURRENT_VERSION = V1;
/* Schema version of this instance */
private final int version = CURRENT_VERSION;
/**
* Limit value to indicate that no limit is to be enforced
*/
public static final int NO_LIMIT = Integer.MAX_VALUE;
/*
* Limit value to indicate that a limit is not to be changed
*/
public static final int NO_CHANGE = -1;
/**
* TableLimit instance to set a table read-only.
*/
public static TableLimits READ_ONLY =
new TableLimits(NO_CHANGE, 0, NO_CHANGE);
/**
* TableLimit instance to disable all read and write accesses to a table
*/
public static TableLimits NO_ACCESS = new TableLimits(0, 0, NO_CHANGE);
/*
* The default populate limit is 100%. This default (vs. NO_LIMIT) prevents
* users from going over their allocation in the case that it is not set.
*/
private static int DEFAULT_POPULATE_LIMIT = 100;
/**
* The limit values. A value less than NO_LIMIT indicates that a limit
* is present and should be enforced. A value of NO_CHANGE indicates that
* that limit should not be changed. Limit objects with NO_CHANGE values
* are used to set values through the API and should not be used for
* enforcement before init() is called.
*/
/* KB/sec */
private int readLimit;
private int writeLimit;
/* GB */
private int sizeLimit;
/* # of indexes */
private int indexLimit;
/* # of child tables */
private int childTableLimit;
/* index key size limit in bytes */
private int indexKeySizeLimit;
/* index population limit in % of read/write limits */
private int indexPopulateLimit;
/**
* Constructs a table limit object. The read and write limits are specified
* in KB/second. Size limit is in GB. A value of NO_LIMIT indicates that
* no limit is enforced. A value of NO_CHANGE will indicate that a limit
* is not changed when this object is applied to an existing table with
* limits.
*
* @param readLimit the read limit in KB/second
* @param writeLimit the write limit in KB/second
* @param sizeLimit the table size limit in GB
* @param maxIndexes the maximum number of indexes
* @param maxChildren the maximum number child tables
* @param indexKeySizeLimit the maximum size of an index key in bytes
* @param indexPopulateLimit the % of throughput that index
* population may consume
*
* @throws IllegalArgumentException if indexPopulateLimitPercent is not
* NO_CHANGE or NO_LIMIT and is less than 1 or greater than 100
*/
public TableLimits(int readLimit, int writeLimit,
int sizeLimit, int maxIndexes,
int maxChildren, int indexKeySizeLimit,
int indexPopulateLimit) {
this.readLimit = readLimit;
this.writeLimit = writeLimit;
this.sizeLimit = sizeLimit;
this.indexLimit = maxIndexes;
this.childTableLimit = maxChildren;
this.indexKeySizeLimit = indexKeySizeLimit;
checkIndexPopulateLimit(indexPopulateLimit);
this.indexPopulateLimit = indexPopulateLimit;
}
/*
* Checks index populate limit. Valid values are 1 through 100, NO_CHANGE,
* and NO_LIMIT.
* TODO - Should NO_LIMIT be allowed?
*/
private void checkIndexPopulateLimit(int value) {
if ((value == NO_CHANGE) || (value == NO_LIMIT)) {
return;
}
if ((value < 1) || (value > 100)) {
throw new IllegalArgumentException("Invalid index populate limit" +
" percent: " + value);
}
}
/**
* Constructs a table limit object. The read and write limits are specified
* in KB/second. Size limit is in GB. A value of NO_LIMIT indicates that
* no limit is enforced. A value of NO_CHANGE will indicate that a limit
* is not changed when this object is applied to an existing table with
* limits.
*
* @param readLimit the read limit in KB/second
* @param writeLimit the write limit in KB/second
* @param sizeLimit the table size limit in GB
* @param maxIndexes the maximum number of indexes
* @param maxChildren the maximum number child tables
* @param indexKeySizeLimit the maximum size of an index key in bytes
*/
public TableLimits(int readLimit, int writeLimit,
int sizeLimit, int maxIndexes,
int maxChildren, int indexKeySizeLimit) {
this(readLimit, writeLimit, sizeLimit,
maxIndexes, maxChildren, indexKeySizeLimit,
NO_CHANGE);
}
/**
* A convenience constructor for a table limit object with only the
* read, write, and size limits. Limits on indexes, child
* tables, or index key size are not changed.
*
* @param readLimit the read limit in KB/second
* @param writeLimit the write limit in KB/second
* @param sizeLimit the table size limit in GB
*/
public TableLimits(int readLimit, int writeLimit, int sizeLimit) {
this(readLimit, writeLimit, sizeLimit,
NO_CHANGE, NO_CHANGE, NO_CHANGE, NO_CHANGE);
}
/**
* A convenience constructor for a table limit object that only sets
* the index populate limit percent.
*/
public TableLimits(int indexPopulateLimit) {
this(NO_CHANGE, NO_CHANGE, NO_CHANGE, NO_CHANGE, NO_CHANGE, NO_CHANGE,
indexPopulateLimit);
}
/*
* Initializes this instance. If any values have not been set (-1)
* they are initialized to their default value or the value from the old
* limits if non-null.
*/
void init(TableLimits oldLimits) {
if (readLimit < 0) {
readLimit = (oldLimits == null) ? NO_LIMIT :
oldLimits.getReadLimit();
}
if (writeLimit < 0) {
writeLimit = (oldLimits == null) ? NO_LIMIT :
oldLimits.getWriteLimit();
}
if (sizeLimit < 0) {
sizeLimit = (oldLimits == null) ? NO_LIMIT :
oldLimits.getSizeLimit();
}
if (indexLimit < 0) {
indexLimit = (oldLimits == null) ? NO_LIMIT :
oldLimits.getIndexLimit();
}
if (childTableLimit < 0) {
childTableLimit = (oldLimits == null) ? NO_LIMIT :
oldLimits.getChildTableLimit();
}
if (indexKeySizeLimit < 0) {
indexKeySizeLimit = (oldLimits == null) ? NO_LIMIT :
oldLimits.getIndexKeySizeLimit();
}
/* See note above on why the default is not NO_LIMIT */
if (indexPopulateLimit < 0) {
indexPopulateLimit = (oldLimits == null) ? DEFAULT_POPULATE_LIMIT :
oldLimits.getIndexPopulateLimit();
}
}
/**
* Returns true if this any limits need to be enforced.
* @return true if this any limits need to be enforced
*/
public boolean hasLimits() {
return hasThroughputLimits() ||
hasSizeLimit() ||
hasIndexLimit() ||
hasChildTableLimit() ||
hasIndexKeySizeLimit();
}
/* -- Throughput Limits -- */
/**
* Gets the read throughput limit.
*
* @return the read throughput limit
*/
public int getReadLimit() {
assert readLimit >= 0;
return readLimit;
}
/**
* Gets the write throughput limit.
*
* @return the write throughput limit
*/
public int getWriteLimit() {
assert writeLimit >= 0;
return writeLimit;
}
public boolean isReadAllowed() {
return readLimit > 0;
}
public boolean isWriteAllowed() {
return writeLimit > 0;
}
/**
* Returns true if either read or write throughput limits are set..
*
* @return true if either read or write throughput limits are set
*/
public boolean hasThroughputLimits() {
assert readLimit >= 0;
assert writeLimit >= 0;
return readLimit < Integer.MAX_VALUE ||
writeLimit < Integer.MAX_VALUE;
}
/**
* Returns true if either of the specified read or write rates have
* exceeded the corresponding limits.
*
* @return true if either of the read or write limits have been exceeded.
*/
public boolean throughputExceeded(long localReadRate, long localWriteRate) {
assert readLimit >= 0;
assert writeLimit >= 0;
return localReadRate > readLimit || localWriteRate > writeLimit;
}
/**
* Gets the index populate limit percentage.
*
* @return the index populate limit percentage or NO_LIMIT.
*/
public int getIndexPopulateLimit() {
assert indexPopulateLimit > 0;
return indexPopulateLimit;
}
/* -- Size Limit -- */
public boolean hasSizeLimit() {
assert sizeLimit >= 0;
return sizeLimit < Integer.MAX_VALUE;
}
/**
* Gets the size limit.
*
* @return the size limit
*/
public int getSizeLimit() {
assert sizeLimit >= 0;
return sizeLimit;
}
/* -- Index Limit -- */
boolean hasIndexLimit() {
assert indexLimit >= 0;
return indexLimit < Integer.MAX_VALUE;
}
int getIndexLimit() {
assert indexLimit >= 0;
return indexLimit;
}
/* -- Child Table Limit -- */
boolean hasChildTableLimit() {
assert childTableLimit >= 0;
return childTableLimit < Integer.MAX_VALUE;
}
int getChildTableLimit() {
assert childTableLimit >= 0;
return childTableLimit;
}
/* -- Index Key Size Limit -- */
public boolean hasIndexKeySizeLimit() {
assert indexKeySizeLimit >= 0;
return indexKeySizeLimit < Integer.MAX_VALUE;
}
public int getIndexKeySizeLimit() {
assert indexKeySizeLimit >= 0;
return indexKeySizeLimit;
}
void putLimits(ObjectNode node) {
if (!hasLimits()) {
return;
}
final ArrayNode array = node.putArray("limits");
final ObjectNode fnode = array.addObject();
if (hasThroughputLimits()) {
fnode.put("readLimit", readLimit);
fnode.put("writeLimit", writeLimit);
}
if (hasSizeLimit()) {
fnode.put("sizeLimit", sizeLimit);
}
if (hasIndexLimit()) {
fnode.put("indexLimit", indexLimit);
}
if (hasChildTableLimit()) {
fnode.put("childTableLimit", childTableLimit);
}
if (hasIndexKeySizeLimit()) {
fnode.put("indexKeySizeLimit", indexKeySizeLimit);
}
}
@SuppressWarnings("unused")
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException {
in.defaultReadObject();
/**
* Checks whether this is a newer version which we don't support. This
* should not happen as the Admin should prevent sending a new
* version out until the store has been upgraded.
*
* Since version is final, Eclipse thinks the throw is dead code,
* requiring the @SuppressWarnings above.
*/
if (version > CURRENT_VERSION) {
throw new IOException("Unknown version: " + version +
", current version is " + CURRENT_VERSION);
}
/*
* A little cheating going on here. The index populate limit was
* added after V1 was released but before TableLimits was used.
* Since 0 is not a possible value, if it is 0 then we know that
* this instance has deserialized from an older version (which
* should not happen). Adding a check for safety.
*/
if (indexPopulateLimit == 0) {
indexPopulateLimit = DEFAULT_POPULATE_LIMIT;
}
}
@Override
public String toString() {
return "TableLimits[" + parseLimit(readLimit) + ", " +
parseLimit(writeLimit) + ", " +
parseLimit(sizeLimit) + ", " +
parseLimit(indexLimit) + ", " +
parseLimit(childTableLimit) + ", " +
parseLimit(indexKeySizeLimit) + ", " +
parseLimit(indexPopulateLimit) + "]";
}
private String parseLimit(int value) {
return (value < 0) ? "NO_CHANGE" :
(value < Integer.MAX_VALUE ? Integer.toString(value) :
"NO_LIMIT");
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy