diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/cluster/metadata/AliasMetaData.java b/modules/elasticsearch/src/main/java/org/elasticsearch/cluster/metadata/AliasMetaData.java index a69f85840ce..b0c0884f581 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/cluster/metadata/AliasMetaData.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/cluster/metadata/AliasMetaData.java @@ -77,6 +77,7 @@ public class AliasMetaData { public Builder(AliasMetaData aliasMetaData) { this(aliasMetaData.alias()); + filter = aliasMetaData.filter(); } public String alias() { diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/index/aliases/IndexAlias.java b/modules/elasticsearch/src/main/java/org/elasticsearch/index/aliases/IndexAlias.java new file mode 100644 index 00000000000..fa01910ee4e --- /dev/null +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/index/aliases/IndexAlias.java @@ -0,0 +1,58 @@ +/* + * Licensed to Elastic Search and Shay Banon under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. Elastic Search 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.aliases; + +import org.apache.lucene.search.Filter; +import org.elasticsearch.common.Nullable; +import org.elasticsearch.common.compress.CompressedString; + +/** + * @author imotov + */ +public class IndexAlias { + + private String alias; + + private CompressedString filter; + + private Filter parsedFilter; + + public IndexAlias(String alias, @Nullable CompressedString filter, @Nullable Filter parsedFilter) { + this.alias = alias; + this.filter = filter; + this.parsedFilter = parsedFilter; + } + + public String alias() { + return alias; + } + + @Nullable + public CompressedString filter() { + return filter; + } + + @Nullable + public Filter parsedFilter() { + return parsedFilter; + } + + +} diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/index/aliases/IndexAliasesService.java b/modules/elasticsearch/src/main/java/org/elasticsearch/index/aliases/IndexAliasesService.java new file mode 100644 index 00000000000..7caf2936911 --- /dev/null +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/index/aliases/IndexAliasesService.java @@ -0,0 +1,140 @@ +/* + * Licensed to Elastic Search and Shay Banon under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. Elastic Search 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.aliases; + +import org.apache.lucene.search.*; +import org.elasticsearch.common.Nullable; +import org.elasticsearch.common.collect.ImmutableMap; +import org.elasticsearch.common.collect.UnmodifiableIterator; +import org.elasticsearch.common.compress.CompressedString; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.lucene.search.XBooleanFilter; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.xcontent.XContentFactory; +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.index.AbstractIndexComponent; +import org.elasticsearch.index.Index; +import org.elasticsearch.index.query.IndexQueryParserService; +import org.elasticsearch.index.query.xcontent.XContentIndexQueryParser; +import org.elasticsearch.index.settings.IndexSettings; +import org.elasticsearch.indices.AliasFilterParsingException; + +import java.io.IOException; +import java.util.List; + +import static org.elasticsearch.common.collect.Lists.newArrayList; +import static org.elasticsearch.common.collect.MapBuilder.newMapBuilder; + +/** + * @author imotov + */ +public class IndexAliasesService extends AbstractIndexComponent implements Iterable { + + private final IndexQueryParserService indexQueryParserService; + + private volatile ImmutableMap aliases = ImmutableMap.of(); + + private final Object mutex = new Object(); + + @Inject public IndexAliasesService(Index index, @IndexSettings Settings indexSettings, IndexQueryParserService indexQueryParserService) { + super(index, indexSettings); + this.indexQueryParserService = indexQueryParserService; + } + + public boolean hasAlias(String alias) { + return aliases.containsKey(alias); + } + + public IndexAlias alias(String alias) { + return aliases.get(alias); + } + + public void add(String alias, @Nullable CompressedString filter) { + add(new IndexAlias(alias, filter, parse(alias, filter))); + } + + public Filter aliasFilter(String... indices) { + List filters = null; + for (String alias : indices) { + // The list contains the index itself - no filtering needed + if (alias.equals(index.name())) { + return null; + } + IndexAlias indexAlias = aliases.get(alias); + if (indexAlias != null) { + // The list contains a non-filtering alias - no filtering needed + if (indexAlias.parsedFilter() == null) { + return null; + } else { + if (filters == null) { + filters = newArrayList(); + } + filters.add(indexAlias.parsedFilter()); + } + } + } + if (filters == null) { + return null; + } + if (filters.size() == 1) { + return filters.get(0); + } else { + XBooleanFilter combined = new XBooleanFilter(); + for (Filter filter : filters) { + combined.add(new FilterClause(filter, BooleanClause.Occur.SHOULD)); + } + return combined; + } + } + + private void add(IndexAlias indexAlias) { + synchronized (mutex) { + aliases = newMapBuilder(aliases).put(indexAlias.alias(), indexAlias).immutableMap(); + } + } + + public void remove(String alias) { + synchronized (mutex) { + aliases = newMapBuilder(aliases).remove(alias).immutableMap(); + } + } + + private Filter parse(String alias, CompressedString filter) { + if (filter == null) { + return null; + } + XContentIndexQueryParser indexQueryParser = (XContentIndexQueryParser) indexQueryParserService.defaultIndexQueryParser(); + try { + byte[] filterSource = filter.uncompressed(); + XContentParser parser = XContentFactory.xContent(filterSource).createParser(filterSource); + try { + return indexQueryParser.parseInnerFilter(parser); + } finally { + parser.close(); + } + } catch (IOException ex) { + throw new AliasFilterParsingException(index, alias, "Invalid alias filter", ex); + } + } + + @Override public UnmodifiableIterator iterator() { + return aliases.values().iterator(); + } +} diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/index/aliases/IndexAliasesServiceModule.java b/modules/elasticsearch/src/main/java/org/elasticsearch/index/aliases/IndexAliasesServiceModule.java new file mode 100644 index 00000000000..b4cffaddd30 --- /dev/null +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/index/aliases/IndexAliasesServiceModule.java @@ -0,0 +1,32 @@ +/* + * Licensed to Elastic Search and Shay Banon under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. Elastic Search 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.aliases; + +import org.elasticsearch.common.inject.AbstractModule; + +/** + * @author imotov + */ +public class IndexAliasesServiceModule extends AbstractModule { + + @Override protected void configure() { + bind(IndexAliasesService.class).asEagerSingleton(); + } +} \ No newline at end of file diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/index/service/IndexService.java b/modules/elasticsearch/src/main/java/org/elasticsearch/index/service/IndexService.java index 454ea3e7f8a..930debe30a9 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/index/service/IndexService.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/index/service/IndexService.java @@ -24,6 +24,7 @@ import org.elasticsearch.common.collect.ImmutableSet; import org.elasticsearch.common.inject.Injector; import org.elasticsearch.index.IndexComponent; import org.elasticsearch.index.IndexShardMissingException; +import org.elasticsearch.index.aliases.IndexAliasesService; import org.elasticsearch.index.analysis.AnalysisService; import org.elasticsearch.index.cache.IndexCache; import org.elasticsearch.index.engine.IndexEngine; @@ -56,6 +57,8 @@ public interface IndexService extends IndexComponent, Iterable { SimilarityService similarityService(); + IndexAliasesService aliasesService(); + IndexEngine engine(); IndexStore store(); diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/index/service/InternalIndexService.java b/modules/elasticsearch/src/main/java/org/elasticsearch/index/service/InternalIndexService.java index c72342d89d0..9bd68b82429 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/index/service/InternalIndexService.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/index/service/InternalIndexService.java @@ -34,6 +34,7 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.env.NodeEnvironment; import org.elasticsearch.gateway.none.NoneGateway; import org.elasticsearch.index.*; +import org.elasticsearch.index.aliases.IndexAliasesService; import org.elasticsearch.index.analysis.AnalysisService; import org.elasticsearch.index.cache.IndexCache; import org.elasticsearch.index.deletionpolicy.DeletionPolicyModule; @@ -103,6 +104,8 @@ public class InternalIndexService extends AbstractIndexComponent implements Inde private final SimilarityService similarityService; + private final IndexAliasesService aliasesService; + private final IndexCache indexCache; private final IndexEngine indexEngine; @@ -118,7 +121,8 @@ public class InternalIndexService extends AbstractIndexComponent implements Inde private volatile boolean closed = false; @Inject public InternalIndexService(Injector injector, Index index, @IndexSettings Settings indexSettings, NodeEnvironment nodeEnv, ThreadPool threadPool, - PercolatorService percolatorService, AnalysisService analysisService, MapperService mapperService, IndexQueryParserService queryParserService, SimilarityService similarityService, + PercolatorService percolatorService, AnalysisService analysisService, MapperService mapperService, + IndexQueryParserService queryParserService, SimilarityService similarityService, IndexAliasesService aliasesService, IndexCache indexCache, IndexEngine indexEngine, IndexGateway indexGateway, IndexStore indexStore) { super(index, indexSettings); this.injector = injector; @@ -130,6 +134,7 @@ public class InternalIndexService extends AbstractIndexComponent implements Inde this.mapperService = mapperService; this.queryParserService = queryParserService; this.similarityService = similarityService; + this.aliasesService = aliasesService; this.indexCache = indexCache; this.indexEngine = indexEngine; this.indexGateway = indexGateway; @@ -203,6 +208,10 @@ public class InternalIndexService extends AbstractIndexComponent implements Inde return similarityService; } + @Override public IndexAliasesService aliasesService() { + return aliasesService; + } + @Override public IndexEngine engine() { return indexEngine; } diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/indices/AliasFilterParsingException.java b/modules/elasticsearch/src/main/java/org/elasticsearch/indices/AliasFilterParsingException.java new file mode 100644 index 00000000000..09fe1a5ffbb --- /dev/null +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/indices/AliasFilterParsingException.java @@ -0,0 +1,39 @@ +/* + * Licensed to Elastic Search and Shay Banon under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. Elastic Search 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.indices; + +import org.elasticsearch.index.Index; +import org.elasticsearch.index.IndexException; + +/** + * @author imotov + */ +public class AliasFilterParsingException extends IndexException { + + public AliasFilterParsingException(Index index, String name, String desc) { + super(index, "[" + name + "], " + desc); + } + + public AliasFilterParsingException(Index index, String name, String desc, Throwable ex) { + super(index, "[" + name + "], " + desc, ex); + } + + +} \ No newline at end of file diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/indices/InternalIndicesService.java b/modules/elasticsearch/src/main/java/org/elasticsearch/indices/InternalIndicesService.java index dc7dbeb5bf8..acec7fbe98e 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/indices/InternalIndicesService.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/indices/InternalIndicesService.java @@ -36,6 +36,7 @@ import org.elasticsearch.common.util.concurrent.ThreadSafe; import org.elasticsearch.env.NodeEnvironment; import org.elasticsearch.gateway.Gateway; import org.elasticsearch.index.*; +import org.elasticsearch.index.aliases.IndexAliasesServiceModule; import org.elasticsearch.index.analysis.AnalysisModule; import org.elasticsearch.index.analysis.AnalysisService; import org.elasticsearch.index.cache.CacheStats; @@ -242,6 +243,7 @@ public class InternalIndicesService extends AbstractLifecycleComponent