/*
* Copyright 2013 Eediom Inc.
*
* 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 org.araqne.logstorage.file;
import java.io.File;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.felix.ipojo.annotations.Component;
import org.apache.felix.ipojo.annotations.Invalidate;
import org.apache.felix.ipojo.annotations.Requires;
import org.apache.felix.ipojo.annotations.Validate;
import org.araqne.confdb.ConfigService;
import org.araqne.logstorage.CallbackSet;
import org.araqne.logstorage.DateUtil;
import org.araqne.logstorage.LogFileService;
import org.araqne.logstorage.LogFileServiceRegistry;
import org.araqne.logstorage.LogTableRegistry;
import org.araqne.logstorage.StorageConfig;
import org.araqne.logstorage.TableConfigSpec;
import org.araqne.logstorage.TableSchema;
import org.araqne.logstorage.engine.ConfigUtil;
import org.araqne.logstorage.engine.Constants;
import org.araqne.storage.api.FilePath;
import org.araqne.storage.api.FilePathNameFilter;
import org.araqne.storage.api.StorageManager;
import org.araqne.storage.localfile.LocalFilePath;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Component(name = "logstorage-log-file-service-v2", immediate = true)
public class LogFileServiceV2 implements LogFileService {
private final Logger logger = LoggerFactory.getLogger(LogFileServiceV2.class);
private static final String OPT_STORAGE_CONFIG = "storageConfig";
private static final String OPT_TABLE_NAME = "tableName";
private static final String OPT_DAY = "day";
private static final String OPT_BASE_PATH = "basePath";
private static final String OPT_INDEX_PATH = "indexPath";
private static final String OPT_DATA_PATH = "dataPath";
private static final String OPT_KEY_PATH = "keyPath";
private static final Object OPT_CALLBACK_SET = "callbackSet";
private static final Object OPT_LASTKEY = "lastKey";
private FilePath logDir;
public static class Option extends TreeMap<String, Object> {
private static final long serialVersionUID = 1L;
public Option(StorageConfig config, Map<String, String> tableMetadata, String tableName, FilePath basePath,
FilePath indexPath, FilePath dataPath, FilePath keyPath) {
this.put(OPT_STORAGE_CONFIG, config);
this.putAll(tableMetadata);
this.put(OPT_TABLE_NAME, tableName);
this.put(OPT_BASE_PATH, basePath);
this.put(OPT_INDEX_PATH, indexPath);
this.put(OPT_DATA_PATH, dataPath);
this.put(OPT_KEY_PATH, keyPath);
}
}
@Requires
private LogTableRegistry tableRegistry;
@Requires
private LogFileServiceRegistry registry;
@Requires
private StorageManager storageManager;
@Requires
private ConfigService conf;
@Validate
public void start() {
logDir = storageManager.resolveFilePath(System.getProperty("araqne.data.dir")).newFilePath("araqne-logstorage/log");
logDir = storageManager.resolveFilePath(getStringParameter(Constants.LogStorageDirectory, logDir.getAbsolutePath()));
logDir.mkdirs();
registry.register(this);
}
private String getStringParameter(Constants key, String defaultValue) {
String value = ConfigUtil.get(conf, key);
if (value != null)
return value;
return defaultValue;
}
@Invalidate
public void stop() {
if (registry != null)
registry.unregister(this);
}
@Override
public String getType() {
return "v2";
}
@Override
public long count(FilePath f) {
return LogCounterV2.count(f);
}
@Override
public List<Date> getPartitions(String tableName) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
TableSchema schema = tableRegistry.getTableSchema(tableName, true);
FilePath baseDir = logDir;
if (schema.getPrimaryStorage().getBasePath() != null)
baseDir = storageManager.resolveFilePath(schema.getPrimaryStorage().getBasePath());
FilePath tableDir = baseDir.newFilePath(Integer.toString(schema.getId()));
FilePath[] files = tableDir.listFiles(new FilePathNameFilter() {
@Override
public boolean accept(FilePath dir, String name) {
return name.endsWith(".idx");
}
});
List<Date> dates = new ArrayList<Date>();
if (files != null) {
for (FilePath file : files) {
try {
dates.add(DateUtil.getDay(dateFormat.parse(file.getName().split("\\.")[0])));
} catch (ParseException e) {
logger.error("araqne logstorage: invalid log filename, table {}, {}", tableName, file.getName());
}
}
}
Collections.sort(dates, Collections.reverseOrder());
return dates;
}
@Override
public LogFileWriter newWriter(Map<String, Object> options) {
checkOption(options);
String tableName = (String) options.get(OPT_TABLE_NAME);
Date day = (Date) options.get(OPT_DAY);
FilePath indexPath = getFilePath(options, OPT_INDEX_PATH);
FilePath dataPath = getFilePath(options, OPT_DATA_PATH);
CallbackSet cbSet = (CallbackSet) options.get(OPT_CALLBACK_SET);
AtomicLong lastKey = (AtomicLong) options.get(OPT_LASTKEY);
try {
return new LogFileWriterV2(indexPath, dataPath, cbSet, tableName, day, lastKey);
} catch (Throwable t) {
throw new IllegalStateException("cannot open writer v2: data file - " + dataPath.getAbsolutePath(), t);
}
}
private void checkOption(Map<String, Object> options) {
for (String key : new String[] { OPT_INDEX_PATH, OPT_DATA_PATH }) {
if (!options.containsKey(key))
throw new IllegalArgumentException("LogFileServiceV1: " + key + " must be supplied");
}
}
private FilePath getFilePath(Map<String, Object> options, String optName) {
Object obj = options.get(optName);
if (obj == null)
return (FilePath) obj;
else if (obj instanceof File) {
return new LocalFilePath((File) obj);
} else {
return (FilePath) obj;
}
}
@Override
public LogFileReader newReader(String tableName, Map<String, Object> options) {
checkOption(options);
FilePath indexPath = getFilePath(options, OPT_INDEX_PATH);
FilePath dataPath = getFilePath(options, OPT_DATA_PATH);
try {
return new LogFileReaderV2(tableName, indexPath, dataPath);
} catch (Throwable t) {
throw new IllegalStateException("cannot open reader v2: data file - " + dataPath.getAbsolutePath());
}
}
@Override
public List<TableConfigSpec> getConfigSpecs() {
return Arrays.asList();
}
@Override
public Map<String, String> getConfigs() {
return new HashMap<String, String>();
}
@Override
public void setConfig(String key, String value) {
}
@Override
public void unsetConfig(String key) {
}
@Override
public List<TableConfigSpec> getReplicaConfigSpecs() {
return Arrays.asList();
}
@Override
public List<TableConfigSpec> getSecondaryConfigSpecs() {
return Arrays.asList();
}
}