/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package com.github.geophile.erdo.consolidate; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import static com.github.geophile.erdo.consolidate.Consolidation.Element; import static java.lang.Math.max; abstract class DropLargestConsolidationPlanner extends ConsolidationPlanner { // ConsolidationPlanner interface @Override public String type() { return "dropLargest"; } @Override public boolean planConsolidation(Element newElement) { assert newElement == null : newElement; consolidationElements = new ArrayList<Element>(); // Candidates sorted with largest elements first List<Element> candidates = consolidationSet.nonDurable().availableForConsolidation(); Collections.sort(candidates, LARGEST_ELEMENTS_FIRST); // Compute consolidation size assuming all candidates included. long maxConsolidationSize = 0; long candidateRecords = 0; for (Element element : candidates) { maxConsolidationSize += element.sizeBytes(); candidateRecords += element.count(); } // Remove large candidates and include what's left boolean discard = true; long consolidationRecords = 0; for (Element candidate : candidates) { if (discard) { if (includeCandidate(candidate, maxConsolidationSize)) { discard = false; } else { maxConsolidationSize -= candidate.sizeBytes(); } } if (!discard) { consolidationElements.add(candidate); consolidationRecords += candidate.count(); } } int nElements = consolidationElements.size(); if (nElements < minMaps || maxConsolidationSize < minSize) { if (LOG.isLoggable(Level.FINER)) { consolidationSet.describe(LOG, Level.FINER, "skip dropLargest consolidation"); LOG.log(Level.FINER, "skip dropLargest consolidation: {0} element{1}, {2} records", new Object[]{nElements, nElements == 1 ? "" : "s", consolidationRecords}); } consolidationElements = null; } else { if (LOG.isLoggable(Level.FINE)) { consolidationSet.describe(LOG, Level.FINE, "dropLargest planning"); LOG.log(Level.FINE, "dropLargest planning {0} / {1}: " + "Consolidation candidates: {0}, consolidation: {1}", new Object[]{consolidationRecords, candidateRecords, consolidationElements, consolidationRecords}); } } return consolidationElements != null; } @Override public List<Element> elementsToConsolidate() { return consolidationElements; } // FractalConsolidationPlanner interface public static DropLargestConsolidationPlanner durable(ConsolidationSet consolidationSet, int minConsolidationMaps, int minConsolidationSize) { return new Durable(consolidationSet, minConsolidationMaps, minConsolidationSize); } public static DropLargestConsolidationPlanner nonDurable(ConsolidationSet consolidationSet, int minConsolidationMaps, int minConsolidationSize) { return new NonDurable(consolidationSet, minConsolidationMaps, minConsolidationSize); } // For use by subclasses protected abstract List<Element> consolidationCandidates(); protected DropLargestConsolidationPlanner(ConsolidationSet consolidationSet, boolean inputDurable, boolean outputDurable, int minConsolidationMaps, int minConsolidationSize) { super(consolidationSet, inputDurable, outputDurable); minMaps = max(minConsolidationMaps, 1); minSize = minConsolidationSize; } // For use by this class private boolean includeCandidate(Element candidate, long consolidationSize) { return (float) candidate.sizeBytes() / consolidationSize <= THRESHOLD; } // Class state private static final Logger LOG = Logger.getLogger(DropLargestConsolidationPlanner.class.getName()); private static final float THRESHOLD = 0.5f; private static final Comparator<Element> LARGEST_ELEMENTS_FIRST = new Comparator<Element>() { public int compare(Element x, Element y) { long xSize = x.sizeBytes(); long ySize = y.sizeBytes(); return xSize < ySize ? 1 : xSize > ySize ? -1 : 0; } }; // Object state private final int minMaps; private final long minSize; private List<Element> consolidationElements; // Inner classes private static class Durable extends DropLargestConsolidationPlanner { @Override protected List<Element> consolidationCandidates() { return consolidationSet.durable().availableForConsolidation(); } public Durable(ConsolidationSet consolidationSet, int minConsolidationMaps, int minConsolidationSize) { super(consolidationSet, true, true, minConsolidationMaps, minConsolidationSize); } } private static class NonDurable extends DropLargestConsolidationPlanner { @Override protected List<Element> consolidationCandidates() { return consolidationSet.nonDurable().availableForConsolidation(); } public NonDurable(ConsolidationSet consolidationSet, int minConsolidationMaps, int minConsolidationSize) { super(consolidationSet, false, false, minConsolidationMaps, minConsolidationSize); } } }