com.amazon.redshift.util.RedshiftPropertyMaxResultBufferParser Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of redshift-jdbc42 Show documentation
Show all versions of redshift-jdbc42 Show documentation
Java JDBC 4.2 (JRE 8+) driver for Redshift database
The newest version!
/*
* Copyright (c) 2019, PostgreSQL Global Development Group
* See the LICENSE file in the project root for more information.
*/
package com.amazon.redshift.util;
import java.lang.management.ManagementFactory;
import com.amazon.redshift.logger.LogLevel;
import com.amazon.redshift.logger.RedshiftLogger;
public class RedshiftPropertyMaxResultBufferParser {
private static final RedshiftLogger logger = RedshiftLogger.getDriverLogger();
private static final String[] PERCENT_PHRASES = new String[]{
"p",
"pct",
"percent"
};
/**
* Method to parse value of max result buffer size.
*
* @param value string containing size of bytes with optional multiplier (T, G, M or K) or percent
* value to declare max percent of heap memory to use.
* @return value of max result buffer size.
* @throws RedshiftException Exception when given value can't be parsed.
*/
public static long parseProperty(String value, String propertyName) throws RedshiftException {
long result = -1;
if (checkIfValueContainsPercent(value)) {
result = parseBytePercentValue(value, propertyName);
} else if (checkIfValueExistsToBeParsed(value)) {
result = parseByteValue(value, propertyName);
}
result = adjustResultSize(result);
return result;
}
/**
* Method to check if given value can contain percent declaration of size of max result buffer.
*
* @param value Value to check.
* @return Result if value contains percent.
*/
private static boolean checkIfValueContainsPercent(String value) {
return (value != null) && (getPercentPhraseLengthIfContains(value) != -1);
}
/**
* Method to get percent value of max result buffer size dependable on actual free memory. This
* method doesn't check other possibilities of value declaration.
*
* @param value string containing percent used to define max result buffer.
* @return percent value of max result buffer size.
* @throws RedshiftException Exception when given value can't be parsed.
*/
private static long parseBytePercentValue(String value, String propertyName) throws RedshiftException {
long result = -1;
int length;
if (checkIfValueExistsToBeParsed(value)) {
length = getPercentPhraseLengthIfContains(value);
if (length == -1) {
throwExceptionAboutParsingError(
String.format("Received parameter '%s' can't be parsed. Value received to parse is '%s'", propertyName, value));
}
result = calculatePercentOfMemory(value, length);
}
return result;
}
/**
* Method to get length of percent phrase existing in given string, only if one of phrases exist
* on the length of string.
*
* @param valueToCheck String which is gonna be checked if contains percent phrase.
* @return Length of phrase inside string, returns -1 when no phrase found.
*/
private static int getPercentPhraseLengthIfContains(String valueToCheck) {
int result = -1;
for (String phrase : PERCENT_PHRASES) {
int indx = getPhraseLengthIfContains(valueToCheck, phrase);
if (indx != -1) {
result = indx;
}
}
return result;
}
/**
* Method to get length of given phrase in given string to check, method checks if phrase exist on
* the end of given string.
*
* @param valueToCheck String which gonna be checked if contains phrase.
* @param phrase Phrase to be looked for on the end of given string.
* @return Length of phrase inside string, returns -1 when phrase wasn't found.
*/
private static int getPhraseLengthIfContains(String valueToCheck, String phrase) {
int searchValueLength = phrase.length();
if (valueToCheck.length() > searchValueLength) {
String subValue = valueToCheck.substring(valueToCheck.length() - searchValueLength);
if (subValue.equals(phrase)) {
return searchValueLength;
}
}
return -1;
}
/**
* Method to calculate percent of given max heap memory.
*
* @param value String which contains percent + percent phrase which gonna be used
* during calculations.
* @param percentPhraseLength Length of percent phrase inside given value.
* @return Size of byte buffer based on percent of max heap memory.
*/
private static long calculatePercentOfMemory(String value, int percentPhraseLength) {
String realValue = value.substring(0, value.length() - percentPhraseLength);
double percent = Double.parseDouble(realValue) / 100;
long result = (long) (percent * ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getMax());
return result;
}
/**
* Method to check if given value has any chars to be parsed.
*
* @param value Value to be checked.
* @return Result if value can be parsed.
*/
private static boolean checkIfValueExistsToBeParsed(String value) {
return value != null && value.length() != 0;
}
/**
* Method to get size based on given string value. String can contains just a number or number +
* multiplier sign (like T, G, M or K).
*
* @param value Given string to be parsed.
* @return Size based on given string.
* @throws RedshiftException Exception when given value can't be parsed.
*/
private static long parseByteValue(String value, String propertyName) throws RedshiftException {
long result = -1;
long multiplier = 1;
long mul = 1000;
String realValue;
char sign = value.charAt(value.length() - 1);
switch (sign) {
case 'T':
case 't':
multiplier *= mul;
case 'G':
case 'g':
multiplier *= mul;
case 'M':
case 'm':
multiplier *= mul;
case 'K':
case 'k':
multiplier *= mul;
realValue = value.substring(0, value.length() - 1);
result = Integer.parseInt(realValue) * multiplier;
break;
case '%':
return result;
default:
if (sign >= '0' && sign <= '9') {
result = Long.parseLong(value);
} else {
throwExceptionAboutParsingError( String.format("Received parameter '%s' can't be parsed. Value received to parse is '%s'", propertyName, value));
}
break;
}
return result;
}
/**
* Method to adjust result memory limit size. If given memory is larger than 90% of max heap
* memory then it gonna be reduced to 90% of max heap memory.
*
* @param value Size to be adjusted.
* @return Adjusted size (original size or 90% of max heap memory)
*/
private static long adjustResultSize(long value) {
if (value > 0.9 * ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getMax()) {
long newResult = (long) (0.9 * ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getMax());
if(RedshiftLogger.isEnable() && logger != null)
logger.log(LogLevel.INFO, GT.tr(
"WARNING! Required to allocate {0} bytes, which exceeded possible heap memory size. Assigned {1} bytes as limit.",
String.valueOf(value), String.valueOf(newResult)));
value = newResult;
}
return value;
}
/**
* Method to throw message for parsing MaxResultBuffer.
*
* @param message Message to be added to exception.
* @param values Values to be put inside exception message.
* @throws RedshiftException Exception when given value can't be parsed.
*/
private static void throwExceptionAboutParsingError(String message, Object... values) throws RedshiftException {
throw new RedshiftException(GT.tr(
message,
values),
RedshiftState.SYNTAX_ERROR);
}
}