[STORE] Make a hybrid directory default using `mmapfs` and `niofs`
`mmapfs` is really good for random access but can have sideeffects if memory maps are large depending on the operating system etc. A hybrid solution where only selected files are actually memory mapped but others mostly consumed sequentially brings the best of both worlds and minimizes the memory map impact. This commit mmaps only the `dvd` and `tim` file for fast random access on docvalues and term dictionaries. Closes #6636
This commit is contained in:
parent
b69fa52588
commit
d82a434d10
|
@ -57,8 +57,8 @@ using the index update settings API dynamically.
|
||||||
File system based storage is the default storage used. There are
|
File system based storage is the default storage used. There are
|
||||||
different implementations or _storage types_. The best one for the
|
different implementations or _storage types_. The best one for the
|
||||||
operating environment will be automatically chosen: `mmapfs` on
|
operating environment will be automatically chosen: `mmapfs` on
|
||||||
Solaris/Linux/Windows 64bit, `simplefs` on Windows 32bit, and
|
Windows 64bit, `simplefs` on Windows 32bit, and `default`
|
||||||
`niofs` for the rest.
|
(hybrid `niofs` and `mmapfs`) for the rest.
|
||||||
|
|
||||||
This can be overridden for all indices by adding this to the
|
This can be overridden for all indices by adding this to the
|
||||||
`config/elasticsearch.yml` file:
|
`config/elasticsearch.yml` file:
|
||||||
|
@ -112,6 +112,17 @@ process equal to the size of the file being mapped. Before using this
|
||||||
class, be sure your have plenty of virtual address space.
|
class, be sure your have plenty of virtual address space.
|
||||||
See <<vm-max-map-count>>
|
See <<vm-max-map-count>>
|
||||||
|
|
||||||
|
[[default_fs]]
|
||||||
|
[float]
|
||||||
|
==== Hybrid MMap / NIO FS coming[1.3.0]
|
||||||
|
|
||||||
|
The `default` type stores the shard index on the file system depending on
|
||||||
|
the file type by mapping a file into memory (mmap) or using Java NIO. Currently
|
||||||
|
only the Lucene term dictionary and doc values files are memory mapped to reduce
|
||||||
|
the impact on the operating system. All other files are opened using Lucene `NIOFSDirectory`.
|
||||||
|
Address space settings (<<vm-map-map-count>>) might also apply if your term
|
||||||
|
dictionaries are large.
|
||||||
|
|
||||||
[float]
|
[float]
|
||||||
[[store-memory]]
|
[[store-memory]]
|
||||||
=== Memory
|
=== Memory
|
||||||
|
|
|
@ -51,7 +51,7 @@ curl localhost:9200/_nodes/process?pretty
|
||||||
[[vm-max-map-count]]
|
[[vm-max-map-count]]
|
||||||
==== Virtual memory
|
==== Virtual memory
|
||||||
|
|
||||||
Elasticsearch uses <<mmapfs,`mmapfs`>> by default to store its indices. The default
|
Elasticsearch uses a <<default_fs,`hybrid mmapfs / niofs`>> directory by default to store its indices. The default
|
||||||
operating system limits on mmap counts is likely to be too low, which may
|
operating system limits on mmap counts is likely to be too low, which may
|
||||||
result in out of memory exceptions. On Linux, you can increase the limits by
|
result in out of memory exceptions. On Linux, you can increase the limits by
|
||||||
running the following command as `root`:
|
running the following command as `root`:
|
||||||
|
|
|
@ -28,7 +28,7 @@ public final class RateLimitedFSDirectory extends FilterDirectory {
|
||||||
|
|
||||||
private final StoreRateLimiting.Listener rateListener;
|
private final StoreRateLimiting.Listener rateListener;
|
||||||
|
|
||||||
public RateLimitedFSDirectory(FSDirectory wrapped, StoreRateLimiting.Provider rateLimitingProvider,
|
public RateLimitedFSDirectory(Directory wrapped, StoreRateLimiting.Provider rateLimitingProvider,
|
||||||
StoreRateLimiting.Listener rateListener) {
|
StoreRateLimiting.Listener rateListener) {
|
||||||
super(wrapped);
|
super(wrapped);
|
||||||
this.rateLimitingProvider = rateLimitingProvider;
|
this.rateLimitingProvider = rateLimitingProvider;
|
||||||
|
|
|
@ -39,6 +39,11 @@ public final class StoreUtils {
|
||||||
SimpleFSDirectory simpleFSDirectory = (SimpleFSDirectory)directory;
|
SimpleFSDirectory simpleFSDirectory = (SimpleFSDirectory)directory;
|
||||||
return "simplefs(" + simpleFSDirectory.getDirectory() + ")";
|
return "simplefs(" + simpleFSDirectory.getDirectory() + ")";
|
||||||
}
|
}
|
||||||
|
if (directory instanceof FileSwitchDirectory) {
|
||||||
|
FileSwitchDirectory fileSwitchDirectory = (FileSwitchDirectory) directory;
|
||||||
|
return "default(" + toString(fileSwitchDirectory.getPrimaryDir()) + "," + toString(fileSwitchDirectory.getSecondaryDir()) + ")";
|
||||||
|
}
|
||||||
|
|
||||||
return directory.toString();
|
return directory.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,9 +19,8 @@
|
||||||
|
|
||||||
package org.elasticsearch.index.store;
|
package org.elasticsearch.index.store;
|
||||||
|
|
||||||
import org.apache.lucene.store.CompoundFileDirectory;
|
import org.apache.lucene.store.*;
|
||||||
import org.apache.lucene.store.Directory;
|
import org.elasticsearch.Version;
|
||||||
import org.apache.lucene.store.FilterDirectory;
|
|
||||||
import org.elasticsearch.common.Nullable;
|
import org.elasticsearch.common.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -29,6 +28,10 @@ import org.elasticsearch.common.Nullable;
|
||||||
*/
|
*/
|
||||||
public final class DirectoryUtils {
|
public final class DirectoryUtils {
|
||||||
|
|
||||||
|
static {
|
||||||
|
assert Version.CURRENT.luceneVersion == org.apache.lucene.util.Version.LUCENE_4_9 : "Remove the special case for NRTCachingDirectory - it implements FilterDirectory in 4.10";
|
||||||
|
}
|
||||||
|
|
||||||
private DirectoryUtils() {} // no instance
|
private DirectoryUtils() {} // no instance
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -52,10 +55,16 @@ public final class DirectoryUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Directory getLeafDirectory(FilterDirectory dir) {
|
static final Directory getLeafDirectory(FilterDirectory dir) {
|
||||||
Directory current = dir.getDelegate();
|
Directory current = dir.getDelegate();
|
||||||
while ((current instanceof FilterDirectory)) {
|
while (true) {
|
||||||
current = ((FilterDirectory) current).getDelegate();
|
if ((current instanceof FilterDirectory)) {
|
||||||
|
current = ((FilterDirectory) current).getDelegate();
|
||||||
|
} else if (current instanceof NRTCachingDirectory) { // remove this when we upgrade to Lucene 4.10
|
||||||
|
current = ((NRTCachingDirectory) current).getDelegate();
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return current;
|
return current;
|
||||||
}
|
}
|
||||||
|
@ -78,7 +87,16 @@ public final class DirectoryUtils {
|
||||||
if (dir instanceof FilterDirectory) {
|
if (dir instanceof FilterDirectory) {
|
||||||
d = getLeafDirectory((FilterDirectory) dir);
|
d = getLeafDirectory((FilterDirectory) dir);
|
||||||
}
|
}
|
||||||
if (targetClass.isAssignableFrom(d.getClass())) {
|
if (d instanceof FileSwitchDirectory) {
|
||||||
|
T leaf = getLeaf(((FileSwitchDirectory) d).getPrimaryDir(), targetClass);
|
||||||
|
if (leaf == null) {
|
||||||
|
d = getLeaf(((FileSwitchDirectory) d).getSecondaryDir(), targetClass, defaultValue);
|
||||||
|
} else {
|
||||||
|
d = leaf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d != null && targetClass.isAssignableFrom(d.getClass())) {
|
||||||
return targetClass.cast(d);
|
return targetClass.cast(d);
|
||||||
} else {
|
} else {
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
|
|
|
@ -27,6 +27,7 @@ import org.elasticsearch.common.inject.Module;
|
||||||
import org.elasticsearch.common.inject.Modules;
|
import org.elasticsearch.common.inject.Modules;
|
||||||
import org.elasticsearch.common.inject.SpawnModules;
|
import org.elasticsearch.common.inject.SpawnModules;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.index.store.fs.DefaultFsIndexStoreModule;
|
||||||
import org.elasticsearch.index.store.fs.MmapFsIndexStoreModule;
|
import org.elasticsearch.index.store.fs.MmapFsIndexStoreModule;
|
||||||
import org.elasticsearch.index.store.fs.NioFsIndexStoreModule;
|
import org.elasticsearch.index.store.fs.NioFsIndexStoreModule;
|
||||||
import org.elasticsearch.index.store.fs.SimpleFsIndexStoreModule;
|
import org.elasticsearch.index.store.fs.SimpleFsIndexStoreModule;
|
||||||
|
@ -39,6 +40,51 @@ public class IndexStoreModule extends AbstractModule implements SpawnModules {
|
||||||
|
|
||||||
private final Settings settings;
|
private final Settings settings;
|
||||||
|
|
||||||
|
public static enum Type {
|
||||||
|
NIOFS {
|
||||||
|
public boolean match(String setting) {
|
||||||
|
return super.match(setting) || "nio_fs".equalsIgnoreCase(setting);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
MMAPFS {
|
||||||
|
public boolean match(String setting) {
|
||||||
|
return super.match(setting) || "mmap_fs".equalsIgnoreCase(setting);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
SIMPLEFS {
|
||||||
|
public boolean match(String setting) {
|
||||||
|
return super.match(setting) || "simple_fs".equalsIgnoreCase(setting);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
RAM {
|
||||||
|
public boolean fsStore() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
MEMORY {
|
||||||
|
public boolean fsStore() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
FS,
|
||||||
|
DEFAULT,;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true iff this store type is a filesystem based store.
|
||||||
|
*/
|
||||||
|
public boolean fsStore() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true iff this settings matches the type.
|
||||||
|
*/
|
||||||
|
public boolean match(String setting) {
|
||||||
|
return this.name().equalsIgnoreCase(setting);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public IndexStoreModule(Settings settings) {
|
public IndexStoreModule(Settings settings) {
|
||||||
this.settings = settings;
|
this.settings = settings;
|
||||||
}
|
}
|
||||||
|
@ -46,26 +92,32 @@ public class IndexStoreModule extends AbstractModule implements SpawnModules {
|
||||||
@Override
|
@Override
|
||||||
public Iterable<? extends Module> spawnModules() {
|
public Iterable<? extends Module> spawnModules() {
|
||||||
Class<? extends Module> indexStoreModule = NioFsIndexStoreModule.class;
|
Class<? extends Module> indexStoreModule = NioFsIndexStoreModule.class;
|
||||||
// Same logic as FSDirectory#open ...
|
|
||||||
if ((Constants.WINDOWS || Constants.SUN_OS || Constants.LINUX)
|
if ((Constants.WINDOWS || Constants.SUN_OS || Constants.LINUX)
|
||||||
&& Constants.JRE_IS_64BIT && MMapDirectory.UNMAP_SUPPORTED) {
|
&& Constants.JRE_IS_64BIT && MMapDirectory.UNMAP_SUPPORTED) {
|
||||||
indexStoreModule = MmapFsIndexStoreModule.class;
|
if (Constants.WINDOWS) {
|
||||||
|
indexStoreModule = MmapFsIndexStoreModule.class;
|
||||||
|
} else {
|
||||||
|
// on linux and friends we only mmap dedicated files
|
||||||
|
indexStoreModule = DefaultFsIndexStoreModule.class;
|
||||||
|
}
|
||||||
} else if (Constants.WINDOWS) {
|
} else if (Constants.WINDOWS) {
|
||||||
indexStoreModule = SimpleFsIndexStoreModule.class;
|
indexStoreModule = SimpleFsIndexStoreModule.class;
|
||||||
}
|
}
|
||||||
String storeType = settings.get("index.store.type");
|
String storeType = settings.get("index.store.type");
|
||||||
if ("ram".equalsIgnoreCase(storeType)) {
|
if (Type.RAM.name().equalsIgnoreCase(storeType)) {
|
||||||
indexStoreModule = RamIndexStoreModule.class;
|
indexStoreModule = RamIndexStoreModule.class;
|
||||||
} else if ("memory".equalsIgnoreCase(storeType)) {
|
} else if (Type.MEMORY.match(storeType)) {
|
||||||
indexStoreModule = RamIndexStoreModule.class;
|
indexStoreModule = RamIndexStoreModule.class;
|
||||||
} else if ("fs".equalsIgnoreCase(storeType)) {
|
} else if (Type.FS.match(storeType)) {
|
||||||
// nothing to set here ... (we default to fs)
|
// nothing to set here ... (we default to fs)
|
||||||
} else if ("simplefs".equalsIgnoreCase(storeType) || "simple_fs".equals(storeType)) {
|
} else if (Type.SIMPLEFS.match(storeType)) {
|
||||||
indexStoreModule = SimpleFsIndexStoreModule.class;
|
indexStoreModule = SimpleFsIndexStoreModule.class;
|
||||||
} else if ("niofs".equalsIgnoreCase(storeType) || "nio_fs".equalsIgnoreCase(storeType)) {
|
} else if (Type.NIOFS.match(storeType)) {
|
||||||
indexStoreModule = NioFsIndexStoreModule.class;
|
indexStoreModule = NioFsIndexStoreModule.class;
|
||||||
} else if ("mmapfs".equalsIgnoreCase(storeType) || "mmap_fs".equalsIgnoreCase(storeType)) {
|
} else if (Type.MMAPFS.match(storeType)) {
|
||||||
indexStoreModule = MmapFsIndexStoreModule.class;
|
indexStoreModule = MmapFsIndexStoreModule.class;
|
||||||
|
} else if (Type.DEFAULT.match(storeType)) {
|
||||||
|
indexStoreModule = DefaultFsIndexStoreModule.class;
|
||||||
} else if (storeType != null) {
|
} else if (storeType != null) {
|
||||||
indexStoreModule = settings.getAsClass("index.store.type", indexStoreModule, "org.elasticsearch.index.store.", "IndexStoreModule");
|
indexStoreModule = settings.getAsClass("index.store.type", indexStoreModule, "org.elasticsearch.index.store.", "IndexStoreModule");
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* Licensed to Elasticsearch under one or more contributor
|
||||||
|
* license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright
|
||||||
|
* ownership. Elasticsearch licenses this file to you 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.elasticsearch.index.store.fs;
|
||||||
|
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
|
import org.apache.lucene.store.*;
|
||||||
|
import org.elasticsearch.common.inject.Inject;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.index.settings.IndexSettings;
|
||||||
|
import org.elasticsearch.index.shard.ShardId;
|
||||||
|
import org.elasticsearch.index.store.IndexStore;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public class DefaultFsDirectoryService extends FsDirectoryService {
|
||||||
|
/*
|
||||||
|
* We are mmapping docvalues as well as term dictionaries, all other files are served through NIOFS
|
||||||
|
* this provides good random access performance while not creating unnecessary mmaps for files like stored
|
||||||
|
* fields etc.
|
||||||
|
*/
|
||||||
|
private static final Set<String> PRIMARY_EXTENSIONS = Collections.unmodifiableSet(Sets.newHashSet("dvd", "tim"));
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public DefaultFsDirectoryService(ShardId shardId, @IndexSettings Settings indexSettings, IndexStore indexStore) {
|
||||||
|
super(shardId, indexSettings, indexStore);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Directory newFSDirectory(File location, LockFactory lockFactory) throws IOException {
|
||||||
|
return new FileSwitchDirectory(PRIMARY_EXTENSIONS, new MMapDirectory(location, lockFactory), new NIOFSDirectory(location, lockFactory), true);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* Licensed to Elasticsearch under one or more contributor
|
||||||
|
* license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright
|
||||||
|
* ownership. Elasticsearch licenses this file to you 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.elasticsearch.index.store.fs;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.inject.Inject;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.env.NodeEnvironment;
|
||||||
|
import org.elasticsearch.index.Index;
|
||||||
|
import org.elasticsearch.index.service.IndexService;
|
||||||
|
import org.elasticsearch.index.settings.IndexSettings;
|
||||||
|
import org.elasticsearch.index.store.DirectoryService;
|
||||||
|
import org.elasticsearch.indices.store.IndicesStore;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public final class DefaultFsIndexStore extends FsIndexStore {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public DefaultFsIndexStore(Index index, @IndexSettings Settings indexSettings, IndexService indexService, IndicesStore indicesStore, NodeEnvironment nodeEnv) {
|
||||||
|
super(index, indexSettings, indexService, indicesStore, nodeEnv);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends DirectoryService> shardDirectory() {
|
||||||
|
return DefaultFsDirectoryService.class;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* Licensed to Elasticsearch under one or more contributor
|
||||||
|
* license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright
|
||||||
|
* ownership. Elasticsearch licenses this file to you 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.elasticsearch.index.store.fs;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.inject.AbstractModule;
|
||||||
|
import org.elasticsearch.index.store.IndexStore;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class DefaultFsIndexStoreModule extends AbstractModule {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure() {
|
||||||
|
bind(IndexStore.class).to(DefaultFsIndexStore.class).asEagerSingleton();
|
||||||
|
}
|
||||||
|
}
|
|
@ -126,13 +126,13 @@ public abstract class FsDirectoryService extends AbstractIndexShardComponent imp
|
||||||
Directory[] dirs = new Directory[locations.length];
|
Directory[] dirs = new Directory[locations.length];
|
||||||
for (int i = 0; i < dirs.length; i++) {
|
for (int i = 0; i < dirs.length; i++) {
|
||||||
FileSystemUtils.mkdirs(locations[i]);
|
FileSystemUtils.mkdirs(locations[i]);
|
||||||
FSDirectory wrapped = newFSDirectory(locations[i], buildLockFactory());
|
Directory wrapped = newFSDirectory(locations[i], buildLockFactory());
|
||||||
dirs[i] = new RateLimitedFSDirectory(wrapped, this, this) ;
|
dirs[i] = new RateLimitedFSDirectory(wrapped, this, this) ;
|
||||||
}
|
}
|
||||||
return dirs;
|
return dirs;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract FSDirectory newFSDirectory(File location, LockFactory lockFactory) throws IOException;
|
protected abstract Directory newFSDirectory(File location, LockFactory lockFactory) throws IOException;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void onPause(long nanos) {
|
public final void onPause(long nanos) {
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
package org.elasticsearch.index.store.fs;
|
package org.elasticsearch.index.store.fs;
|
||||||
|
|
||||||
import org.apache.lucene.store.FSDirectory;
|
import org.apache.lucene.store.Directory;
|
||||||
import org.apache.lucene.store.LockFactory;
|
import org.apache.lucene.store.LockFactory;
|
||||||
import org.apache.lucene.store.MMapDirectory;
|
import org.apache.lucene.store.MMapDirectory;
|
||||||
import org.elasticsearch.common.inject.Inject;
|
import org.elasticsearch.common.inject.Inject;
|
||||||
|
@ -41,7 +41,7 @@ public class MmapFsDirectoryService extends FsDirectoryService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected FSDirectory newFSDirectory(File location, LockFactory lockFactory) throws IOException {
|
protected Directory newFSDirectory(File location, LockFactory lockFactory) throws IOException {
|
||||||
return new MMapDirectory(location, buildLockFactory());
|
return new MMapDirectory(location, buildLockFactory());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
package org.elasticsearch.index.store.fs;
|
package org.elasticsearch.index.store.fs;
|
||||||
|
|
||||||
import org.apache.lucene.store.FSDirectory;
|
import org.apache.lucene.store.Directory;
|
||||||
import org.apache.lucene.store.LockFactory;
|
import org.apache.lucene.store.LockFactory;
|
||||||
import org.apache.lucene.store.NIOFSDirectory;
|
import org.apache.lucene.store.NIOFSDirectory;
|
||||||
import org.elasticsearch.common.inject.Inject;
|
import org.elasticsearch.common.inject.Inject;
|
||||||
|
@ -41,7 +41,7 @@ public class NioFsDirectoryService extends FsDirectoryService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected FSDirectory newFSDirectory(File location, LockFactory lockFactory) throws IOException {
|
protected Directory newFSDirectory(File location, LockFactory lockFactory) throws IOException {
|
||||||
return new NIOFSDirectory(location, lockFactory);
|
return new NIOFSDirectory(location, lockFactory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
package org.elasticsearch.index.store.fs;
|
package org.elasticsearch.index.store.fs;
|
||||||
|
|
||||||
import org.apache.lucene.store.FSDirectory;
|
import org.apache.lucene.store.Directory;
|
||||||
import org.apache.lucene.store.LockFactory;
|
import org.apache.lucene.store.LockFactory;
|
||||||
import org.apache.lucene.store.SimpleFSDirectory;
|
import org.apache.lucene.store.SimpleFSDirectory;
|
||||||
import org.elasticsearch.common.inject.Inject;
|
import org.elasticsearch.common.inject.Inject;
|
||||||
|
@ -41,7 +41,7 @@ public class SimpleFsDirectoryService extends FsDirectoryService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected FSDirectory newFSDirectory(File location, LockFactory lockFactory) throws IOException {
|
protected Directory newFSDirectory(File location, LockFactory lockFactory) throws IOException {
|
||||||
return new SimpleFSDirectory(location, lockFactory);
|
return new SimpleFSDirectory(location, lockFactory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
/*
|
||||||
|
* Licensed to Elasticsearch under one or more contributor
|
||||||
|
* license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright
|
||||||
|
* ownership. Elasticsearch licenses this file to you 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.elasticsearch.index.store;
|
||||||
|
|
||||||
|
import com.carrotsearch.randomizedtesting.LifecycleScope;
|
||||||
|
import com.carrotsearch.randomizedtesting.annotations.Repeat;
|
||||||
|
import com.carrotsearch.randomizedtesting.annotations.Seed;
|
||||||
|
import org.apache.lucene.store.*;
|
||||||
|
import org.elasticsearch.test.ElasticsearchLuceneTestCase;
|
||||||
|
import org.elasticsearch.test.ElasticsearchTestCase;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.*;
|
||||||
|
|
||||||
|
public class DirectoryUtilsTest extends ElasticsearchLuceneTestCase {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetLeave() throws IOException {
|
||||||
|
File file = ElasticsearchTestCase.newTempDir(LifecycleScope.TEST);
|
||||||
|
final int iters = scaledRandomIntBetween(10, 100);
|
||||||
|
for (int i = 0; i < iters; i++) {
|
||||||
|
{
|
||||||
|
BaseDirectoryWrapper dir = newFSDirectory(file);
|
||||||
|
FSDirectory directory = DirectoryUtils.getLeaf(new FilterDirectory(dir) {}, FSDirectory.class, null);
|
||||||
|
assertThat(directory, notNullValue());
|
||||||
|
assertThat(directory, sameInstance(DirectoryUtils.getLeafDirectory(dir)));
|
||||||
|
dir.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
BaseDirectoryWrapper dir = newFSDirectory(file);
|
||||||
|
FSDirectory directory = DirectoryUtils.getLeaf(dir, FSDirectory.class, null);
|
||||||
|
assertThat(directory, notNullValue());
|
||||||
|
assertThat(directory, sameInstance(DirectoryUtils.getLeafDirectory(dir)));
|
||||||
|
dir.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Set<String> stringSet = Collections.emptySet();
|
||||||
|
BaseDirectoryWrapper dir = newFSDirectory(file);
|
||||||
|
FSDirectory directory = DirectoryUtils.getLeaf(new FileSwitchDirectory(stringSet, dir, dir, random().nextBoolean()), FSDirectory.class, null);
|
||||||
|
assertThat(directory, notNullValue());
|
||||||
|
assertThat(directory, sameInstance(DirectoryUtils.getLeafDirectory(dir)));
|
||||||
|
dir.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Set<String> stringSet = Collections.emptySet();
|
||||||
|
BaseDirectoryWrapper dir = newFSDirectory(file);
|
||||||
|
FSDirectory directory = DirectoryUtils.getLeaf(new FilterDirectory(new FileSwitchDirectory(stringSet, dir, dir, random().nextBoolean())) {}, FSDirectory.class, null);
|
||||||
|
assertThat(directory, notNullValue());
|
||||||
|
assertThat(directory, sameInstance(DirectoryUtils.getLeafDirectory(dir)));
|
||||||
|
dir.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Set<String> stringSet = Collections.emptySet();
|
||||||
|
BaseDirectoryWrapper dir = newFSDirectory(file);
|
||||||
|
RAMDirectory directory = DirectoryUtils.getLeaf(new FilterDirectory(new FileSwitchDirectory(stringSet, dir, dir, random().nextBoolean())) {}, RAMDirectory.class, null);
|
||||||
|
assertThat(directory, nullValue());
|
||||||
|
dir.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,6 +22,7 @@ package org.elasticsearch.indices.store;
|
||||||
import org.apache.lucene.store.Directory;
|
import org.apache.lucene.store.Directory;
|
||||||
import org.elasticsearch.env.NodeEnvironment;
|
import org.elasticsearch.env.NodeEnvironment;
|
||||||
import org.elasticsearch.index.shard.service.InternalIndexShard;
|
import org.elasticsearch.index.shard.service.InternalIndexShard;
|
||||||
|
import org.elasticsearch.index.store.IndexStoreModule;
|
||||||
import org.elasticsearch.indices.IndicesService;
|
import org.elasticsearch.indices.IndicesService;
|
||||||
import org.elasticsearch.test.ElasticsearchIntegrationTest;
|
import org.elasticsearch.test.ElasticsearchIntegrationTest;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
@ -39,19 +40,19 @@ import static org.hamcrest.Matchers.*;
|
||||||
*/
|
*/
|
||||||
public class SimpleDistributorTests extends ElasticsearchIntegrationTest {
|
public class SimpleDistributorTests extends ElasticsearchIntegrationTest {
|
||||||
|
|
||||||
public final static String[] STORE_TYPES = {"fs", "simplefs", "niofs", "mmapfs"};
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAvailableSpaceDetection() {
|
public void testAvailableSpaceDetection() {
|
||||||
for (String store : STORE_TYPES) {
|
for (IndexStoreModule.Type store : IndexStoreModule.Type.values()) {
|
||||||
createIndexWithStoreType("test", store, StrictDistributor.class.getCanonicalName());
|
if (store.fsStore()) {
|
||||||
|
createIndexWithStoreType("test", store, StrictDistributor.class.getCanonicalName());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDirectoryToString() throws IOException {
|
public void testDirectoryToString() throws IOException {
|
||||||
internalCluster().wipeTemplates(); // no random settings please
|
internalCluster().wipeTemplates(); // no random settings please
|
||||||
createIndexWithStoreType("test", "niofs", "least_used");
|
createIndexWithStoreType("test", IndexStoreModule.Type.NIOFS, "least_used");
|
||||||
String storeString = getStoreDirectory("test", 0).toString();
|
String storeString = getStoreDirectory("test", 0).toString();
|
||||||
logger.info(storeString);
|
logger.info(storeString);
|
||||||
File[] dataPaths = dataPaths();
|
File[] dataPaths = dataPaths();
|
||||||
|
@ -61,7 +62,7 @@ public class SimpleDistributorTests extends ElasticsearchIntegrationTest {
|
||||||
}
|
}
|
||||||
assertThat(storeString, endsWith(", type=MERGE, rate=20.0)])"));
|
assertThat(storeString, endsWith(", type=MERGE, rate=20.0)])"));
|
||||||
|
|
||||||
createIndexWithStoreType("test", "niofs", "random");
|
createIndexWithStoreType("test", IndexStoreModule.Type.NIOFS, "random");
|
||||||
storeString = getStoreDirectory("test", 0).toString();
|
storeString = getStoreDirectory("test", 0).toString();
|
||||||
logger.info(storeString);
|
logger.info(storeString);
|
||||||
dataPaths = dataPaths();
|
dataPaths = dataPaths();
|
||||||
|
@ -71,7 +72,7 @@ public class SimpleDistributorTests extends ElasticsearchIntegrationTest {
|
||||||
}
|
}
|
||||||
assertThat(storeString, endsWith(", type=MERGE, rate=20.0)])"));
|
assertThat(storeString, endsWith(", type=MERGE, rate=20.0)])"));
|
||||||
|
|
||||||
createIndexWithStoreType("test", "mmapfs", "least_used");
|
createIndexWithStoreType("test", IndexStoreModule.Type.MMAPFS, "least_used");
|
||||||
storeString = getStoreDirectory("test", 0).toString();
|
storeString = getStoreDirectory("test", 0).toString();
|
||||||
logger.info(storeString);
|
logger.info(storeString);
|
||||||
dataPaths = dataPaths();
|
dataPaths = dataPaths();
|
||||||
|
@ -81,7 +82,7 @@ public class SimpleDistributorTests extends ElasticsearchIntegrationTest {
|
||||||
}
|
}
|
||||||
assertThat(storeString, endsWith(", type=MERGE, rate=20.0)])"));
|
assertThat(storeString, endsWith(", type=MERGE, rate=20.0)])"));
|
||||||
|
|
||||||
createIndexWithStoreType("test", "simplefs", "least_used");
|
createIndexWithStoreType("test", IndexStoreModule.Type.SIMPLEFS, "least_used");
|
||||||
storeString = getStoreDirectory("test", 0).toString();
|
storeString = getStoreDirectory("test", 0).toString();
|
||||||
logger.info(storeString);
|
logger.info(storeString);
|
||||||
dataPaths = dataPaths();
|
dataPaths = dataPaths();
|
||||||
|
@ -91,13 +92,25 @@ public class SimpleDistributorTests extends ElasticsearchIntegrationTest {
|
||||||
}
|
}
|
||||||
assertThat(storeString, endsWith(", type=MERGE, rate=20.0)])"));
|
assertThat(storeString, endsWith(", type=MERGE, rate=20.0)])"));
|
||||||
|
|
||||||
createIndexWithStoreType("test", "memory", "least_used");
|
createIndexWithStoreType("test", IndexStoreModule.Type.DEFAULT, "least_used");
|
||||||
|
storeString = getStoreDirectory("test", 0).toString();
|
||||||
|
logger.info(storeString);
|
||||||
|
dataPaths = dataPaths();
|
||||||
|
assertThat(storeString.toLowerCase(Locale.ROOT), startsWith("store(least_used[rate_limited(default(mmapfs(" + dataPaths[0].getAbsolutePath().toLowerCase(Locale.ROOT)));
|
||||||
|
assertThat(storeString.toLowerCase(Locale.ROOT), containsString("),niofs(" + dataPaths[0].getAbsolutePath().toLowerCase(Locale.ROOT)));
|
||||||
|
|
||||||
|
if (dataPaths.length > 1) {
|
||||||
|
assertThat(storeString.toLowerCase(Locale.ROOT), containsString("), rate_limited(default(mmapfs(" + dataPaths[1].getAbsolutePath().toLowerCase(Locale.ROOT)));
|
||||||
|
}
|
||||||
|
assertThat(storeString, endsWith(", type=MERGE, rate=20.0)])"));
|
||||||
|
|
||||||
|
createIndexWithStoreType("test", IndexStoreModule.Type.MEMORY, "least_used");
|
||||||
storeString = getStoreDirectory("test", 0).toString();
|
storeString = getStoreDirectory("test", 0).toString();
|
||||||
logger.info(storeString);
|
logger.info(storeString);
|
||||||
dataPaths = dataPaths();
|
dataPaths = dataPaths();
|
||||||
assertThat(storeString, equalTo("store(least_used[ram])"));
|
assertThat(storeString, equalTo("store(least_used[ram])"));
|
||||||
|
|
||||||
createIndexWithoutRateLimitingStoreType("test", "niofs", "least_used");
|
createIndexWithoutRateLimitingStoreType("test", IndexStoreModule.Type.NIOFS, "least_used");
|
||||||
storeString = getStoreDirectory("test", 0).toString();
|
storeString = getStoreDirectory("test", 0).toString();
|
||||||
logger.info(storeString);
|
logger.info(storeString);
|
||||||
dataPaths = dataPaths();
|
dataPaths = dataPaths();
|
||||||
|
@ -108,12 +121,12 @@ public class SimpleDistributorTests extends ElasticsearchIntegrationTest {
|
||||||
assertThat(storeString, endsWith(")])"));
|
assertThat(storeString, endsWith(")])"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createIndexWithStoreType(String index, String storeType, String distributor) {
|
private void createIndexWithStoreType(String index, IndexStoreModule.Type storeType, String distributor) {
|
||||||
cluster().wipeIndices(index);
|
cluster().wipeIndices(index);
|
||||||
client().admin().indices().prepareCreate(index)
|
client().admin().indices().prepareCreate(index)
|
||||||
.setSettings(settingsBuilder()
|
.setSettings(settingsBuilder()
|
||||||
.put("index.store.distributor", distributor)
|
.put("index.store.distributor", distributor)
|
||||||
.put("index.store.type", storeType)
|
.put("index.store.type", storeType.name())
|
||||||
.put("index.number_of_replicas", 0)
|
.put("index.number_of_replicas", 0)
|
||||||
.put("index.number_of_shards", 1)
|
.put("index.number_of_shards", 1)
|
||||||
)
|
)
|
||||||
|
@ -121,7 +134,7 @@ public class SimpleDistributorTests extends ElasticsearchIntegrationTest {
|
||||||
assertThat(client().admin().cluster().prepareHealth("test").setWaitForGreenStatus().execute().actionGet().isTimedOut(), equalTo(false));
|
assertThat(client().admin().cluster().prepareHealth("test").setWaitForGreenStatus().execute().actionGet().isTimedOut(), equalTo(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createIndexWithoutRateLimitingStoreType(String index, String storeType, String distributor) {
|
private void createIndexWithoutRateLimitingStoreType(String index, IndexStoreModule.Type storeType, String distributor) {
|
||||||
cluster().wipeIndices(index);
|
cluster().wipeIndices(index);
|
||||||
client().admin().indices().prepareCreate(index)
|
client().admin().indices().prepareCreate(index)
|
||||||
.setSettings(settingsBuilder()
|
.setSettings(settingsBuilder()
|
||||||
|
|
|
@ -31,10 +31,7 @@ import org.elasticsearch.common.util.concurrent.ConcurrentCollections;
|
||||||
import org.elasticsearch.index.shard.ShardId;
|
import org.elasticsearch.index.shard.ShardId;
|
||||||
import org.elasticsearch.index.store.DirectoryService;
|
import org.elasticsearch.index.store.DirectoryService;
|
||||||
import org.elasticsearch.index.store.IndexStore;
|
import org.elasticsearch.index.store.IndexStore;
|
||||||
import org.elasticsearch.index.store.fs.FsDirectoryService;
|
import org.elasticsearch.index.store.fs.*;
|
||||||
import org.elasticsearch.index.store.fs.MmapFsDirectoryService;
|
|
||||||
import org.elasticsearch.index.store.fs.NioFsDirectoryService;
|
|
||||||
import org.elasticsearch.index.store.fs.SimpleFsDirectoryService;
|
|
||||||
import org.elasticsearch.index.store.ram.RamDirectoryService;
|
import org.elasticsearch.index.store.ram.RamDirectoryService;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -107,13 +104,15 @@ public class MockDirectoryHelper {
|
||||||
} else if (Constants.WINDOWS) {
|
} else if (Constants.WINDOWS) {
|
||||||
return new SimpleFsDirectoryService(shardId, indexSettings, indexStore);
|
return new SimpleFsDirectoryService(shardId, indexSettings, indexStore);
|
||||||
}
|
}
|
||||||
switch (random.nextInt(3)) {
|
switch (random.nextInt(4)) {
|
||||||
case 1:
|
case 2:
|
||||||
return new MmapFsDirectoryService(shardId, indexSettings, indexStore);
|
return new DefaultFsDirectoryService(shardId, indexSettings, indexStore);
|
||||||
case 0:
|
case 1:
|
||||||
return new SimpleFsDirectoryService(shardId, indexSettings, indexStore);
|
return new MmapFsDirectoryService(shardId, indexSettings, indexStore);
|
||||||
default:
|
case 0:
|
||||||
return new NioFsDirectoryService(shardId, indexSettings, indexStore);
|
return new SimpleFsDirectoryService(shardId, indexSettings, indexStore);
|
||||||
|
default:
|
||||||
|
return new NioFsDirectoryService(shardId, indexSettings, indexStore);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,6 @@ package org.elasticsearch.test.store;
|
||||||
import com.google.common.base.Charsets;
|
import com.google.common.base.Charsets;
|
||||||
import org.apache.lucene.index.CheckIndex;
|
import org.apache.lucene.index.CheckIndex;
|
||||||
import org.apache.lucene.store.Directory;
|
import org.apache.lucene.store.Directory;
|
||||||
import org.apache.lucene.store.FSDirectory;
|
|
||||||
import org.apache.lucene.store.LockFactory;
|
import org.apache.lucene.store.LockFactory;
|
||||||
import org.elasticsearch.common.Nullable;
|
import org.elasticsearch.common.Nullable;
|
||||||
import org.elasticsearch.common.inject.Inject;
|
import org.elasticsearch.common.inject.Inject;
|
||||||
|
@ -82,7 +81,7 @@ public class MockFSDirectoryService extends FsDirectoryService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected synchronized FSDirectory newFSDirectory(File location, LockFactory lockFactory) throws IOException {
|
protected synchronized Directory newFSDirectory(File location, LockFactory lockFactory) throws IOException {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue