improve multiple data locations when reading checksums and local gateway state files by going through all the locations to find them.

This commit is contained in:
Shay Banon 2011-09-23 17:08:21 +03:00
parent 49d976fc41
commit f74793c92a
2 changed files with 150 additions and 124 deletions

View File

@ -73,7 +73,7 @@ import static org.elasticsearch.common.util.concurrent.EsExecutors.*;
*/
public class LocalGateway extends AbstractLifecycleComponent<Gateway> implements Gateway, ClusterStateListener {
private File location;
private boolean requiresStatePersistence;
private final ClusterService clusterService;
@ -184,8 +184,7 @@ public class LocalGateway extends AbstractLifecycleComponent<Gateway> implements
}
@Override public void clusterChanged(final ClusterChangedEvent event) {
// the location is set to null, so we should not store it (for example, its not a data/master node)
if (location == null) {
if (!requiresStatePersistence) {
return;
}
@ -260,20 +259,18 @@ public class LocalGateway extends AbstractLifecycleComponent<Gateway> implements
// if this is not a possible master node or data node, bail, we won't save anything here...
if (!clusterService.localNode().masterNode() && !clusterService.localNode().dataNode()) {
location = null;
requiresStatePersistence = false;
} else {
// create the location where the state will be stored
// TODO: we might want to persist states on all data locations
this.location = new File(nodeEnv.nodeDataLocations()[0], "_state");
FileSystemUtils.mkdirs(this.location);
requiresStatePersistence = true;
if (clusterService.localNode().masterNode()) {
try {
long version = findLatestMetaStateVersion();
if (version != -1) {
File file = new File(location, "metadata-" + version);
logger.debug("[find_latest_state]: loading metadata from [{}]", file.getAbsolutePath());
this.currentMetaState = readMetaState(Streams.copyToByteArray(new FileInputStream(file)));
File latest = findLatestMetaStateVersion();
if (latest != null) {
logger.debug("[find_latest_state]: loading metadata from [{}]", latest.getAbsolutePath());
this.currentMetaState = readMetaState(Streams.copyToByteArray(new FileInputStream(latest)));
} else {
logger.debug("[find_latest_state]: no metadata state loaded");
}
@ -284,11 +281,10 @@ public class LocalGateway extends AbstractLifecycleComponent<Gateway> implements
if (clusterService.localNode().dataNode()) {
try {
long version = findLatestStartedShardsVersion();
if (version != -1) {
File file = new File(location, "shards-" + version);
logger.debug("[find_latest_state]: loading started shards from [{}]", file.getAbsolutePath());
this.currentStartedShards = readStartedShards(Streams.copyToByteArray(new FileInputStream(file)));
File latest = findLatestStartedShardsVersion();
if (latest != null) {
logger.debug("[find_latest_state]: loading started shards from [{}]", latest.getAbsolutePath());
this.currentStartedShards = readStartedShards(Streams.copyToByteArray(new FileInputStream(latest)));
} else {
logger.debug("[find_latest_state]: no started shards loaded");
}
@ -299,9 +295,19 @@ public class LocalGateway extends AbstractLifecycleComponent<Gateway> implements
}
}
private long findLatestStartedShardsVersion() throws IOException {
private File findLatestStartedShardsVersion() throws IOException {
long index = -1;
for (File stateFile : location.listFiles()) {
File latest = null;
for (File dataLocation : nodeEnv.nodeDataLocations()) {
File stateLocation = new File(dataLocation, "_state");
if (!stateLocation.exists()) {
continue;
}
File[] stateFiles = stateLocation.listFiles();
if (stateFiles == null) {
continue;
}
for (File stateFile : stateFiles) {
if (logger.isTraceEnabled()) {
logger.trace("[find_latest_state]: processing [" + stateFile.getName() + "]");
}
@ -319,18 +325,29 @@ public class LocalGateway extends AbstractLifecycleComponent<Gateway> implements
}
readStartedShards(data);
index = fileIndex;
latest = stateFile;
} catch (IOException e) {
logger.warn("[find_latest_state]: failed to read state from [" + name + "], ignoring...", e);
}
}
}
return index;
}
return latest;
}
private long findLatestMetaStateVersion() throws IOException {
private File findLatestMetaStateVersion() throws IOException {
long index = -1;
for (File stateFile : location.listFiles()) {
File latest = null;
for (File dataLocation : nodeEnv.nodeDataLocations()) {
File stateLocation = new File(dataLocation, "_state");
if (!stateLocation.exists()) {
continue;
}
File[] stateFiles = stateLocation.listFiles();
if (stateFiles == null) {
continue;
}
for (File stateFile : stateFiles) {
if (logger.isTraceEnabled()) {
logger.trace("[find_latest_state]: processing [" + stateFile.getName() + "]");
}
@ -349,13 +366,14 @@ public class LocalGateway extends AbstractLifecycleComponent<Gateway> implements
}
readMetaState(data);
index = fileIndex;
latest = stateFile;
} catch (IOException e) {
logger.warn("[find_latest_state]: failed to read state from [" + name + "], ignoring...", e);
}
}
}
return index;
}
return latest;
}
private LocalGatewayMetaState readMetaState(byte[] data) throws IOException {
@ -411,7 +429,11 @@ public class LocalGateway extends AbstractLifecycleComponent<Gateway> implements
builder.metaData(event.state().metaData());
try {
File stateFile = new File(location, "metadata-" + version);
File stateLocation = new File(nodeEnv.nodeDataLocations()[0], "_state");
if (!stateLocation.exists()) {
FileSystemUtils.mkdirs(stateLocation);
}
File stateFile = new File(stateLocation, "metadata-" + version);
OutputStream fos = new FileOutputStream(stateFile);
if (compress) {
fos = new LZFOutputStream(fos);
@ -432,7 +454,12 @@ public class LocalGateway extends AbstractLifecycleComponent<Gateway> implements
currentMetaState = stateToWrite;
// delete all the other files
File[] files = location.listFiles(new FilenameFilter() {
for (File dataLocation : nodeEnv.nodeDataLocations()) {
stateLocation = new File(dataLocation, "_state");
if (!stateLocation.exists()) {
continue;
}
File[] files = stateLocation.listFiles(new FilenameFilter() {
@Override public boolean accept(File dir, String name) {
return name.startsWith("metadata-") && !name.equals("metadata-" + version);
}
@ -442,6 +469,7 @@ public class LocalGateway extends AbstractLifecycleComponent<Gateway> implements
file.delete();
}
}
}
} catch (IOException e) {
logger.warn("failed to write updated state", e);
@ -461,7 +489,11 @@ public class LocalGateway extends AbstractLifecycleComponent<Gateway> implements
@Override public void run() {
try {
File stateFile = new File(location, "shards-" + event.state().version());
File stateLocation = new File(nodeEnv.nodeDataLocations()[0], "_state");
if (!stateLocation.exists()) {
FileSystemUtils.mkdirs(stateLocation);
}
File stateFile = new File(stateLocation, "shards-" + event.state().version());
OutputStream fos = new FileOutputStream(stateFile);
if (compress) {
fos = new LZFOutputStream(fos);
@ -487,7 +519,12 @@ public class LocalGateway extends AbstractLifecycleComponent<Gateway> implements
}
// delete all the other files
File[] files = location.listFiles(new FilenameFilter() {
for (File dataLocation : nodeEnv.nodeDataLocations()) {
File stateLocation = new File(dataLocation, "_state");
if (!stateLocation.exists()) {
continue;
}
File[] files = stateLocation.listFiles(new FilenameFilter() {
@Override public boolean accept(File dir, String name) {
return name.startsWith("shards-") && !name.equals("shards-" + event.state().version());
}
@ -500,3 +537,4 @@ public class LocalGateway extends AbstractLifecycleComponent<Gateway> implements
}
}
}
}

View File

@ -25,8 +25,8 @@ import org.apache.lucene.store.IndexInput;
import org.apache.lucene.store.IndexOutput;
import org.apache.lucene.store.Lock;
import org.apache.lucene.store.LockFactory;
import org.apache.lucene.store.SimpleFSDirectory;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.Unicode;
import org.elasticsearch.common.collect.ImmutableList;
import org.elasticsearch.common.collect.ImmutableMap;
import org.elasticsearch.common.collect.MapBuilder;
@ -164,22 +164,29 @@ public class Store extends AbstractIndexShardComponent {
}
public static Map<String, String> readChecksums(File[] locations) throws IOException {
for (File location : locations) {
FSDirectory directory = FSDirectory.open(location);
Directory[] dirs = new Directory[locations.length];
try {
Map<String, String> checksums = readChecksums(directory, null);
if (checksums != null) {
return checksums;
for (int i = 0; i < locations.length; i++) {
dirs[i] = new SimpleFSDirectory(locations[i]);
}
return readChecksums(dirs, null);
} finally {
directory.close();
for (Directory dir : dirs) {
if (dir != null) {
try {
dir.close();
} catch (IOException e) {
// ignore
}
}
}
}
return null;
}
static Map<String, String> readChecksums(Directory dir, Map<String, String> defaultValue) throws IOException {
static Map<String, String> readChecksums(Directory[] dirs, Map<String, String> defaultValue) throws IOException {
long lastFound = -1;
Directory lastDir = null;
for (Directory dir : dirs) {
for (String name : dir.listAll()) {
if (!isChecksum(name)) {
continue;
@ -187,12 +194,14 @@ public class Store extends AbstractIndexShardComponent {
long current = Long.parseLong(name.substring(CHECKSUMS_PREFIX.length()));
if (current > lastFound) {
lastFound = current;
lastDir = dir;
}
}
}
if (lastFound == -1) {
return defaultValue;
}
IndexInput indexInput = dir.openInput(CHECKSUMS_PREFIX + lastFound);
IndexInput indexInput = lastDir.openInput(CHECKSUMS_PREFIX + lastFound);
try {
indexInput.readInt(); // version
return indexInput.readStringStringMap();
@ -205,10 +214,6 @@ public class Store extends AbstractIndexShardComponent {
}
public void writeChecksums() throws IOException {
writeChecksums(directory);
}
private void writeChecksums(StoreDirectory dir) throws IOException {
String checksumName = CHECKSUMS_PREFIX + System.currentTimeMillis();
ImmutableMap<String, StoreFileMetaData> files = list();
synchronized (mutex) {
@ -218,7 +223,7 @@ public class Store extends AbstractIndexShardComponent {
checksums.put(metaData.name(), metaData.checksum());
}
}
IndexOutput output = dir.createOutput(checksumName, false);
IndexOutput output = directory.createOutput(checksumName, false);
output.writeInt(0); // version
output.writeStringStringMap(checksums);
output.close();
@ -226,7 +231,7 @@ public class Store extends AbstractIndexShardComponent {
for (StoreFileMetaData metaData : files.values()) {
if (metaData.name().startsWith(CHECKSUMS_PREFIX) && !checksumName.equals(metaData.name())) {
try {
dir.deleteFileChecksum(metaData.name());
directory.deleteFileChecksum(metaData.name());
} catch (Exception e) {
// ignore
}
@ -282,30 +287,10 @@ public class Store extends AbstractIndexShardComponent {
this.delegates = delegates;
synchronized (mutex) {
MapBuilder<String, StoreFileMetaData> builder = MapBuilder.newMapBuilder();
Map<String, String> checksums = readChecksums(delegates[0], new HashMap<String, String>());
Map<String, String> checksums = readChecksums(delegates, new HashMap<String, String>());
for (Directory delegate : delegates) {
for (String file : delegate.listAll()) {
// BACKWARD CKS SUPPORT
if (file.endsWith(".cks")) { // ignore checksum files here
continue;
}
String checksum = checksums.get(file);
// BACKWARD CKS SUPPORT
if (checksum == null) {
if (delegate.fileExists(file + ".cks")) {
IndexInput indexInput = delegate.openInput(file + ".cks");
try {
if (indexInput.length() > 0) {
byte[] checksumBytes = new byte[(int) indexInput.length()];
indexInput.readBytes(checksumBytes, 0, checksumBytes.length, false);
checksum = Unicode.fromBytes(checksumBytes);
}
} finally {
indexInput.close();
}
}
}
builder.put(file, new StoreFileMetaData(file, delegate.fileLength(file), delegate.fileModified(file), checksum, delegate));
}
}
@ -350,13 +335,16 @@ public class Store extends AbstractIndexShardComponent {
}
public void deleteFileChecksum(String name) throws IOException {
StoreFileMetaData metaData = filesMetadata.get(name);
if (metaData != null) {
try {
delegates[0].deleteFile(name);
metaData.directory().deleteFile(name);
} catch (IOException e) {
if (delegates[0].fileExists(name)) {
if (metaData.directory().fileExists(name)) {
throw e;
}
}
}
synchronized (mutex) {
filesMetadata = MapBuilder.newMapBuilder(filesMetadata).remove(name).immutableMap();
files = filesMetadata.keySet().toArray(new String[filesMetadata.size()]);