/*
* Copyright 2014, Stratio.
*
* 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 com.stratio.cassandra.index;
import com.google.common.base.Objects;
import com.stratio.cassandra.index.schema.Schema;
import org.apache.cassandra.config.CFMetaData;
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.utils.ByteBufferUtil;
import java.io.File;
import java.util.Map;
/**
* Class for building {@link com.stratio.cassandra.index.service.RowService} instances.
*
* @author Andres de la Pena <adelapena@stratio.com>
*/
public class RowIndexConfig {
private static final String SCHEMA_OPTION = "schema";
private static final String REFRESH_SECONDS_OPTION = "refresh_seconds";
private static final double DEFAULT_REFRESH_SECONDS = 60;
private static final String INDEXES_DIR_NAME = "lucene";
private static final String RAM_BUFFER_MB_OPTION = "ram_buffer_mb";
private static final int DEFAULT_RAM_BUFFER_MB = 64;
private static final String MAX_MERGE_MB_OPTION = "max_merge_mb";
private static final int DEFAULT_MAX_MERGE_MB = 5;
private static final String MAX_CACHED_MB_OPTION = "max_cached_mb";
private static final int DEFAULT_MAX_CACHED_MB = 30;
private static final String INDEXING_THREADS_OPTION = "indexing_threads";
private static final int DEFAULT_INDEXING_THREADS = 0;
private static final String INDEXING_QUEUES_SIZE_OPTION = "indexing_queues_size";
private static final int DEFAULT_INDEXING_QUEUES_SIZE = 50;
private final Schema schema;
private final double refreshSeconds;
private final String path;
private final int ramBufferMB;
private final int maxMergeMB;
private final int maxCachedMB;
private final int indexingThreads;
private final int indexingQueuesSize;
/**
* Builds a new {@link RowIndexConfig} for the column family defined by the specified metadata using the specified
* index options.
*
* @param metadata The metadata of the indexed column family.
* @param options The index options.
*/
public RowIndexConfig(CFMetaData metadata, Map<String, String> options) {
// Setup refresh seconds
String refreshOption = options.get(REFRESH_SECONDS_OPTION);
if (refreshOption != null) {
try {
refreshSeconds = Double.parseDouble(refreshOption);
} catch (NumberFormatException e) {
String msg = String.format("'%s' must be a strictly positive double", REFRESH_SECONDS_OPTION);
throw new RuntimeException(msg);
}
if (refreshSeconds <= 0) {
String msg = String.format("'%s' must be strictly positive", REFRESH_SECONDS_OPTION);
throw new RuntimeException(msg);
}
} else {
refreshSeconds = DEFAULT_REFRESH_SECONDS;
}
// Setup write buffer size
String ramBufferSizeOption = options.get(RAM_BUFFER_MB_OPTION);
if (ramBufferSizeOption != null) {
try {
ramBufferMB = Integer.parseInt(ramBufferSizeOption);
} catch (NumberFormatException e) {
String msg = String.format("'%s' must be a strictly positive integer", RAM_BUFFER_MB_OPTION);
throw new RuntimeException(msg);
}
if (ramBufferMB <= 0) {
String msg = String.format("'%s' must be strictly positive", RAM_BUFFER_MB_OPTION);
throw new RuntimeException(msg);
}
} else {
ramBufferMB = DEFAULT_RAM_BUFFER_MB;
}
// Setup max merge size
String maxMergeSizeMBOption = options.get(MAX_MERGE_MB_OPTION);
if (maxMergeSizeMBOption != null) {
try {
maxMergeMB = Integer.parseInt(maxMergeSizeMBOption);
} catch (NumberFormatException e) {
String msg = String.format("'%s' must be a strictly positive integer", MAX_MERGE_MB_OPTION);
throw new RuntimeException(msg);
}
if (maxMergeMB <= 0) {
String msg = String.format("'%s' must be strictly positive", MAX_MERGE_MB_OPTION);
throw new RuntimeException(msg);
}
} else {
maxMergeMB = DEFAULT_MAX_MERGE_MB;
}
// Setup max cached MB
String maxCachedMBOption = options.get(MAX_CACHED_MB_OPTION);
if (maxCachedMBOption != null) {
try {
maxCachedMB = Integer.parseInt(maxCachedMBOption);
} catch (NumberFormatException e) {
String msg = String.format("'%s' must be a strictly positive integer", MAX_CACHED_MB_OPTION);
throw new RuntimeException(msg);
}
if (maxCachedMB <= 0) {
String msg = String.format("'%s' must be strictly positive", MAX_CACHED_MB_OPTION);
throw new RuntimeException(msg);
}
} else {
maxCachedMB = DEFAULT_MAX_CACHED_MB;
}
// Setup queues in index pool
String indexPoolNumQueuesOption = options.get(INDEXING_THREADS_OPTION);
if (indexPoolNumQueuesOption != null) {
try {
indexingThreads = Integer.parseInt(indexPoolNumQueuesOption);
} catch (NumberFormatException e) {
String msg = String.format("'%s' must be a positive integer", INDEXING_THREADS_OPTION);
throw new RuntimeException(msg);
}
} else {
indexingThreads = DEFAULT_INDEXING_THREADS;
}
// Setup queues in index pool
String indexPoolQueuesSizeOption = options.get(INDEXING_QUEUES_SIZE_OPTION);
if (indexPoolQueuesSizeOption != null) {
try {
indexingQueuesSize = Integer.parseInt(indexPoolQueuesSizeOption);
} catch (NumberFormatException e) {
String msg = String.format("'%s' must be a strictly positive integer", INDEXING_QUEUES_SIZE_OPTION);
throw new RuntimeException(msg);
}
if (indexingQueuesSize <= 0) {
String msg = String.format("'%s' must be strictly positive", INDEXING_QUEUES_SIZE_OPTION);
throw new RuntimeException(msg);
}
} else {
indexingQueuesSize = DEFAULT_INDEXING_QUEUES_SIZE;
}
// Get columns mapping schema
String schemaOption = options.get(SCHEMA_OPTION);
if (schemaOption != null && !schemaOption.trim().isEmpty()) {
try {
schema = Schema.fromJson(schemaOption);
schema.validate(metadata);
} catch (Exception e) {
String msg = String.format("'%s' is invalid : %s", SCHEMA_OPTION, e.getMessage());
throw new RuntimeException(msg);
}
} else {
String msg = String.format("'%s' required", SCHEMA_OPTION);
throw new RuntimeException(msg);
}
// Get Lucene directory path
String[] dataFileLocations = DatabaseDescriptor.getAllDataFileLocations();
StringBuilder directoryPathBuilder = new StringBuilder();
directoryPathBuilder.append(dataFileLocations[0]);
directoryPathBuilder.append(File.separatorChar);
directoryPathBuilder.append(metadata.ksName);
directoryPathBuilder.append(File.separatorChar);
directoryPathBuilder.append(metadata.cfName);
directoryPathBuilder.append("-");
directoryPathBuilder.append(ByteBufferUtil.bytesToHex(ByteBufferUtil.bytes(metadata.cfId)));
directoryPathBuilder.append(File.separatorChar);
directoryPathBuilder.append(INDEXES_DIR_NAME);
path = directoryPathBuilder.toString();
}
public Schema getSchema() {
return schema;
}
public double getRefreshSeconds() {
return refreshSeconds;
}
public String getPath() {
return path;
}
public int getRamBufferMB() {
return ramBufferMB;
}
public int getMaxMergeMB() {
return maxMergeMB;
}
public int getMaxCachedMB() {
return maxCachedMB;
}
public int getIndexingThreads() {
return indexingThreads;
}
public int getIndexingQueuesSize() {
return indexingQueuesSize;
}
/** {@inheritDoc} */
@Override
public String toString() {
return Objects.toStringHelper(this)
.add("schema", schema)
.add("refreshSeconds", refreshSeconds)
.add("path", path)
.add("ramBufferMB", ramBufferMB)
.add("maxMergeMB", maxMergeMB)
.add("maxCachedMB", maxCachedMB)
.add("indexingThreads", indexingThreads)
.add("indexingQueuesSize", indexingQueuesSize)
.toString();
}
}