/** * Copyright (C) 2009-2013 FoundationDB, LLC * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.foundationdb.server.store.statistics; import com.foundationdb.ais.model.Index; import com.foundationdb.ais.model.IndexColumn; import com.foundationdb.server.service.session.Session; import com.foundationdb.server.store.IndexVisitor; import java.util.ArrayList; import java.util.List; public class IndexStatisticsVisitor<K extends Comparable<? super K>, V> extends IndexVisitor<K,V> { public interface VisitorCreator<K extends Comparable<? super K>, V> { IndexStatisticsGenerator<K,V> multiColumnVisitor(Index index); IndexStatisticsGenerator<K,V> singleColumnVisitor(Session session, IndexColumn indexColumn); } public IndexStatisticsVisitor(Session session, Index index, long indexRowCount, long estimatedSampleCount, VisitorCreator<K,V> creator) { this.index = index; this.indexRowCount = indexRowCount; this.estimatedSampleCount = estimatedSampleCount; this.multiColumnVisitor = creator.multiColumnVisitor(index); this.nIndexColumns = index.getKeyColumns().size(); this.singleColumnVisitors = new ArrayList<>(nIndexColumns-1); // Single column 0 is handled as leading column of multi-column. for (int f = 1; f < nIndexColumns; f++) { singleColumnVisitors.add( creator.singleColumnVisitor(session, index.getKeyColumns().get(f)) ); } } public void init(int bucketCount) { multiColumnVisitor.init(bucketCount, estimatedSampleCount); for (int c = 1; c < nIndexColumns; c++) { singleColumnVisitors.get(c-1).init(bucketCount, estimatedSampleCount); } } public void finish(int bucketCount) { multiColumnVisitor.finish(bucketCount); for (int c = 1; c < nIndexColumns; c++) { singleColumnVisitors.get(c-1).finish(bucketCount); } } protected void visit(K key, V value) { multiColumnVisitor.visit(key, value); for (int c = 1; c < nIndexColumns; c++) { singleColumnVisitors.get(c-1).visit(key, value); } } public IndexStatistics getIndexStatistics() { IndexStatistics indexStatistics = new IndexStatistics(index); // The multi-column visitor has the sampled row count. The single-column visitors // have the count of distinct sampled keys for that column. int sampledCount = multiColumnVisitor.rowCount(); indexStatistics.setRowCount(indexRowCount); indexStatistics.setSampledCount(sampledCount); multiColumnVisitor.getIndexStatistics(indexStatistics); for (int c = 1; c < nIndexColumns; c++) { singleColumnVisitors.get(c-1).getIndexStatistics(indexStatistics); } return indexStatistics; } private final Index index; private final long indexRowCount, estimatedSampleCount; private final IndexStatisticsGenerator<K,V> multiColumnVisitor; private final List<IndexStatisticsGenerator<K,V>> singleColumnVisitors; private final int nIndexColumns; }