/*
* Copyright 2016 The Simple File Server Authors
*
* 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.sfs.elasticsearch.container;
import io.vertx.core.logging.Logger;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.IndexNotFoundException;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.SingleBucketAggregation;
import org.elasticsearch.search.aggregations.bucket.global.GlobalBuilder;
import org.elasticsearch.search.aggregations.metrics.sum.Sum;
import org.sfs.Server;
import org.sfs.VertxContext;
import org.sfs.elasticsearch.Elasticsearch;
import org.sfs.elasticsearch.Jsonify;
import org.sfs.vo.ContainerStats;
import org.sfs.vo.PersistentContainer;
import rx.Observable;
import rx.functions.Func1;
import static com.google.common.collect.FluentIterable.from;
import static io.vertx.core.logging.LoggerFactory.getLogger;
import static java.lang.String.format;
import static org.elasticsearch.common.unit.TimeValue.timeValueMillis;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.search.aggregations.AggregationBuilders.filter;
import static org.elasticsearch.search.aggregations.AggregationBuilders.global;
import static org.elasticsearch.search.aggregations.AggregationBuilders.nested;
import static org.elasticsearch.search.aggregations.AggregationBuilders.sum;
import static org.sfs.util.ExceptionHelper.containsException;
import static rx.Observable.error;
import static rx.Observable.just;
public class LoadContainerStats implements Func1<PersistentContainer, Observable<ContainerStats>> {
private static final Logger LOGGER = getLogger(LoadContainerStats.class);
private final VertxContext<Server> vertxContext;
public LoadContainerStats(VertxContext<Server> vertxContext) {
this.vertxContext = vertxContext;
}
@Override
public Observable<ContainerStats> call(PersistentContainer persistentContainer) {
final Elasticsearch elasticSearch = vertxContext.verticle().elasticsearch();
String containerId = persistentContainer.getId();
GlobalBuilder aggregation =
global("all_objects")
.subAggregation(
filter("filter_by_container")
.filter(termQuery("container_id", containerId))
.subAggregation(
nested("nested_segments")
.path("versions.segments")
.subAggregation(
sum("bytes_used")
.field("versions.segments.read_length")
)
)
);
String objectIndex = elasticSearch.objectIndex(persistentContainer.getName());
SearchRequestBuilder aggregateRequest = elasticSearch.get()
.prepareSearch(objectIndex)
.setTypes(elasticSearch.defaultType())
.setSize(0)
.addAggregation(aggregation)
.setTimeout(timeValueMillis(elasticSearch.getDefaultSearchTimeout() - 10));
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(format("Search Request = %s", Jsonify.toString(aggregateRequest)));
}
return elasticSearch.execute(vertxContext, aggregateRequest, elasticSearch.getDefaultSearchTimeout())
.map(oSearchResponse -> {
SearchResponse searchResponse = oSearchResponse.get();
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(format("Search Response = %s", Jsonify.toString(searchResponse)));
}
long objectCount = 0;
double bytesUsed = 0;
for (SingleBucketAggregation globalAgg : toSingleBucket(searchResponse.getAggregations())) {
if ("all_objects".equals(globalAgg.getName())) {
for (SingleBucketAggregation filterAgg : toSingleBucket(globalAgg.getAggregations())) {
if ("filter_by_container".equals(filterAgg.getName())) {
objectCount += filterAgg.getDocCount();
for (SingleBucketAggregation nestAgg : toSingleBucket(filterAgg.getAggregations())) {
if ("nested_segments".equals(nestAgg.getName())) {
for (Aggregation bytesUsedAgg : nestAgg.getAggregations()) {
if ("bytes_used".equals(bytesUsedAgg.getName())) {
Sum sum = (Sum) bytesUsedAgg;
bytesUsed += sum.getValue();
}
}
}
}
}
}
}
}
return new ContainerStats(bytesUsed, objectCount, persistentContainer);
})
.onErrorResumeNext(throwable -> {
if (containsException(IndexNotFoundException.class, throwable)) {
return just(new ContainerStats(0, 0, persistentContainer));
} else {
return error(throwable);
}
});
}
protected Iterable<SingleBucketAggregation> toSingleBucket(Aggregations aggregations) {
return from(aggregations)
.transform(input -> (SingleBucketAggregation) input);
}
}