Search in sources :

Example 21 with ContainerStorageStats

use of com.github.ambry.server.storagestats.ContainerStorageStats in project ambry by linkedin.

the class BlobStoreStats method getContainerStorageStats.

/**
 * Gets the storage stats for all serviceIds and their containerIds as of now (the time when the API is called).
 * Storage stats is comprised of 3 values: 1. valid data size (logicalStorageUsage) 2. physical data size 3. number of blobs.
 * The following data are considered as valid data for this API:
 * 1. PUT with no expiry and no corresponding DELETE
 * 2. PUT expiring at t_exp but t_exp_ref < t_exp
 * 3. PUT with corresponding DELETE at time t_delete but t_del_ref < t_delete
 * For this API, t_ref is specified by the given reference time.
 * For physical data size, all the records will be taken into consideration, including DELETED PUT, even DELETE record itself.
 * For number of blobs, it includes all different blob ids.
 * @param referenceTimeInMs the reference time in ms until which deletes and expiration are relevant
 * @return the storage stats of each container in the form of a nested {@link Map} of accountId to another map of containerId
 * to {@link ContainerStorageStats}.
 */
Map<Short, Map<Short, ContainerStorageStats>> getContainerStorageStats(long referenceTimeInMs) throws StoreException {
    if (!enabled.get()) {
        throw new StoreException(String.format("BlobStoreStats is not enabled or closing for store %s", storeId), StoreErrorCodes.Store_Shutting_Down);
    }
    Map<Short, Map<Short, Long>> validSizeMap = null;
    Map<Short, Map<Short, Long>> physicalUsageMap = null;
    Map<Short, Map<Short, Long>> numberStoreKeyMap = null;
    ScanResults currentScanResults = scanResults.get();
    if (currentScanResults != null && isWithinRange(currentScanResults.containerForecastStartTimeMs, currentScanResults.containerForecastEndTimeMs, referenceTimeInMs)) {
        validSizeMap = currentScanResults.getValidSizePerContainer(referenceTimeInMs);
        physicalUsageMap = currentScanResults.getContainerPhysicalStorageUsage();
        numberStoreKeyMap = currentScanResults.getContainerNumberOfStoreKeys();
    } else {
        if (isScanning && isWithinRange(indexScanner.newScanResults.containerForecastStartTimeMs, indexScanner.newScanResults.containerForecastEndTimeMs, referenceTimeInMs)) {
            scanLock.lock();
            try {
                if (isScanning) {
                    if (waitCondition.await(waitTimeoutInSecs, TimeUnit.SECONDS)) {
                        currentScanResults = scanResults.get();
                        if (isWithinRange(currentScanResults.containerForecastStartTimeMs, currentScanResults.containerForecastEndTimeMs, referenceTimeInMs)) {
                            validSizeMap = currentScanResults.getValidSizePerContainer(referenceTimeInMs);
                            physicalUsageMap = currentScanResults.getContainerPhysicalStorageUsage();
                            numberStoreKeyMap = currentScanResults.getContainerNumberOfStoreKeys();
                        }
                    } else {
                        metrics.blobStoreStatsIndexScannerErrorCount.inc();
                        logger.error("Timed out while waiting for BlobStoreStats index scan to complete for store {}", storeId);
                    }
                } else {
                    currentScanResults = scanResults.get();
                    if (isWithinRange(currentScanResults.containerForecastStartTimeMs, currentScanResults.containerForecastEndTimeMs, referenceTimeInMs)) {
                        validSizeMap = currentScanResults.getValidSizePerContainer(referenceTimeInMs);
                        physicalUsageMap = currentScanResults.getContainerPhysicalStorageUsage();
                        numberStoreKeyMap = currentScanResults.getContainerNumberOfStoreKeys();
                    }
                }
            } catch (InterruptedException e) {
                metrics.blobStoreStatsIndexScannerErrorCount.inc();
                throw new IllegalStateException(String.format("Illegal state, wait for scan to complete is interrupted for store %s", storeId), e);
            } finally {
                scanLock.unlock();
            }
        }
        if (validSizeMap == null) {
            // 3. rare edge case where currentScanResults updated twice since the start of the wait.
            return collectContainerStorageStats(referenceTimeInMs);
        }
    }
    Map<Short, Map<Short, ContainerStorageStats>> retValue = new HashMap<>();
    for (short accountId : validSizeMap.keySet()) {
        for (short containerId : validSizeMap.get(accountId).keySet()) {
            retValue.computeIfAbsent(accountId, k -> new HashMap<>()).put(containerId, new ContainerStorageStats(containerId, validSizeMap.get(accountId).get(containerId), physicalUsageMap.get(accountId).get(containerId), numberStoreKeyMap.get(accountId).get(containerId)));
        }
    }
    return retValue;
}
Also used : ScheduledFuture(java.util.concurrent.ScheduledFuture) ListIterator(java.util.ListIterator) LoggerFactory(org.slf4j.LoggerFactory) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) HashMap(java.util.HashMap) AtomicReference(java.util.concurrent.atomic.AtomicReference) ContainerStorageStats(com.github.ambry.server.storagestats.ContainerStorageStats) ArrayList(java.util.ArrayList) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Map(java.util.Map) SystemTime(com.github.ambry.utils.SystemTime) ScheduledExecutorService(java.util.concurrent.ScheduledExecutorService) Time(com.github.ambry.utils.Time) EnumSet(java.util.EnumSet) StatsUtils(com.github.ambry.store.StatsUtils) StoreConfig(com.github.ambry.config.StoreConfig) Logger(org.slf4j.Logger) Pair(com.github.ambry.utils.Pair) Iterator(java.util.Iterator) ReentrantLock(java.util.concurrent.locks.ReentrantLock) Predicate(java.util.function.Predicate) Collection(java.util.Collection) ConcurrentNavigableMap(java.util.concurrent.ConcurrentNavigableMap) Utils(com.github.ambry.utils.Utils) NavigableMap(java.util.NavigableMap) LinkedBlockingQueue(java.util.concurrent.LinkedBlockingQueue) Objects(java.util.Objects) TimeUnit(java.util.concurrent.TimeUnit) List(java.util.List) Condition(java.util.concurrent.locks.Condition) TreeMap(java.util.TreeMap) Closeable(java.io.Closeable) Queue(java.util.Queue) SortedMap(java.util.SortedMap) ContainerStorageStats(com.github.ambry.server.storagestats.ContainerStorageStats) HashMap(java.util.HashMap) HashMap(java.util.HashMap) Map(java.util.Map) ConcurrentNavigableMap(java.util.concurrent.ConcurrentNavigableMap) NavigableMap(java.util.NavigableMap) TreeMap(java.util.TreeMap) SortedMap(java.util.SortedMap)

Example 22 with ContainerStorageStats

use of com.github.ambry.server.storagestats.ContainerStorageStats in project ambry by linkedin.

the class BlobStoreStats method getContainerStorageStats.

@Override
public Map<Short, Map<Short, ContainerStorageStats>> getContainerStorageStats(long referenceTimeInMs, List<Short> accountIdsToExclude) throws StoreException {
    Map<Short, Map<Short, ContainerStorageStats>> containerStatsMap = getContainerStorageStats(referenceTimeInMs);
    if (accountIdsToExclude != null && !accountIdsToExclude.isEmpty()) {
        accountIdsToExclude.forEach(id -> containerStatsMap.remove(id));
    }
    // Remove zero storage stats
    List<Short> accountIdToRemove = new ArrayList<>();
    List<Short> containerIdToRemove = new ArrayList<>();
    for (short accountId : containerStatsMap.keySet()) {
        containerIdToRemove.clear();
        for (short containerId : containerStatsMap.get(accountId).keySet()) {
            ContainerStorageStats stats = containerStatsMap.get(accountId).get(containerId);
            if (stats.isEmpty()) {
                containerIdToRemove.add(containerId);
            }
        }
        for (short containerId : containerIdToRemove) {
            containerStatsMap.get(accountId).remove(containerId);
        }
        if (containerStatsMap.get(accountId).size() == 0) {
            accountIdToRemove.add(accountId);
        }
    }
    for (short accountId : accountIdToRemove) {
        containerStatsMap.remove(accountId);
    }
    return containerStatsMap;
}
Also used : ContainerStorageStats(com.github.ambry.server.storagestats.ContainerStorageStats) ArrayList(java.util.ArrayList) HashMap(java.util.HashMap) Map(java.util.Map) ConcurrentNavigableMap(java.util.concurrent.ConcurrentNavigableMap) NavigableMap(java.util.NavigableMap) TreeMap(java.util.TreeMap) SortedMap(java.util.SortedMap)

Example 23 with ContainerStorageStats

use of com.github.ambry.server.storagestats.ContainerStorageStats in project ambry by linkedin.

the class BlobStoreStats method collectContainerStorageStats.

/**
 * Walk through the entire index and collect storage stats per container.
 * @param referenceTimeInMs the reference time in ms until which deletes and expiration are relevant
 * @return a nested {@link Map} of serviceId to containerId to {@link ContainerStorageStats}.
 */
private Map<Short, Map<Short, ContainerStorageStats>> collectContainerStorageStats(long referenceTimeInMs) throws StoreException {
    logger.trace("On demand index scanning to collect container valid data sizes for store {} wrt ref time {}", storeId, referenceTimeInMs);
    long startTimeMs = time.milliseconds();
    Map<StoreKey, IndexFinalState> keyFinalStates = new HashMap<>();
    Map<Short, Map<Short, Long>> validDataSizePerContainer = new HashMap<>();
    Map<Short, Map<Short, Long>> physicalDataSizePerContainer = new HashMap<>();
    Map<Short, Map<Short, Long>> storeKeysPerContainer = new HashMap<>();
    Map<Short, Map<Short, ContainerStorageStats>> result = new HashMap<>();
    int indexSegmentCount = 0;
    for (IndexSegment indexSegment : index.getIndexSegments().descendingMap().values()) {
        if (!enabled.get()) {
            throw new StoreException(String.format("BlobStoreStats is not enabled or closing for store %s", storeId), StoreErrorCodes.Store_Shutting_Down);
        }
        long indexSegmentStartProcessTimeMs = time.milliseconds();
        diskIOScheduler.getSlice(BlobStoreStats.IO_SCHEDULER_JOB_TYPE, BlobStoreStats.IO_SCHEDULER_JOB_ID, indexSegment.size());
        forEachIndexEntry(indexSegment, referenceTimeInMs, time.milliseconds(), null, keyFinalStates, true, (entry, isValid) -> {
            IndexValue indexValue = entry.getValue();
            if (isValid && indexValue.isPut()) {
                // delete and TTL update records does not count towards valid data size for usage (containers)
                updateNestedMapHelper(validDataSizePerContainer, indexValue.getAccountId(), indexValue.getContainerId(), indexValue.getSize());
            }
            updateNestedMapHelper(physicalDataSizePerContainer, indexValue.getAccountId(), indexValue.getContainerId(), indexValue.getSize());
            updateNestedMapHelper(storeKeysPerContainer, indexValue.getAccountId(), indexValue.getContainerId(), (long) (indexValue.isPut() ? 1 : 0));
        });
        metrics.statsOnDemandScanTimePerIndexSegmentMs.update(time.milliseconds() - indexSegmentStartProcessTimeMs, TimeUnit.MILLISECONDS);
        indexSegmentCount++;
        if (indexSegmentCount == 1 || indexSegmentCount % 10 == 0) {
            logger.info("Container Stats: Index segment {} processing complete (on-demand scanning) for store {}", indexSegment.getFile().getName(), storeId);
        }
    }
    for (short accountId : validDataSizePerContainer.keySet()) {
        for (short containerId : validDataSizePerContainer.get(accountId).keySet()) {
            result.computeIfAbsent(accountId, k -> new HashMap<>()).put(containerId, new ContainerStorageStats(containerId, validDataSizePerContainer.get(accountId).get(containerId), physicalDataSizePerContainer.get(accountId).get(containerId), storeKeysPerContainer.get(accountId).get(containerId)));
        }
    }
    // The remaining index entries in keyFinalStates are DELETE tombstones left by compaction (whose associated PUT is not found)
    updateDeleteTombstoneStats(keyFinalStates.values());
    metrics.statsOnDemandScanTotalTimeMs.update(time.milliseconds() - startTimeMs, TimeUnit.MILLISECONDS);
    return result;
}
Also used : ScheduledFuture(java.util.concurrent.ScheduledFuture) ListIterator(java.util.ListIterator) LoggerFactory(org.slf4j.LoggerFactory) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) HashMap(java.util.HashMap) AtomicReference(java.util.concurrent.atomic.AtomicReference) ContainerStorageStats(com.github.ambry.server.storagestats.ContainerStorageStats) ArrayList(java.util.ArrayList) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Map(java.util.Map) SystemTime(com.github.ambry.utils.SystemTime) ScheduledExecutorService(java.util.concurrent.ScheduledExecutorService) Time(com.github.ambry.utils.Time) EnumSet(java.util.EnumSet) StatsUtils(com.github.ambry.store.StatsUtils) StoreConfig(com.github.ambry.config.StoreConfig) Logger(org.slf4j.Logger) Pair(com.github.ambry.utils.Pair) Iterator(java.util.Iterator) ReentrantLock(java.util.concurrent.locks.ReentrantLock) Predicate(java.util.function.Predicate) Collection(java.util.Collection) ConcurrentNavigableMap(java.util.concurrent.ConcurrentNavigableMap) Utils(com.github.ambry.utils.Utils) NavigableMap(java.util.NavigableMap) LinkedBlockingQueue(java.util.concurrent.LinkedBlockingQueue) Objects(java.util.Objects) TimeUnit(java.util.concurrent.TimeUnit) List(java.util.List) Condition(java.util.concurrent.locks.Condition) TreeMap(java.util.TreeMap) Closeable(java.io.Closeable) Queue(java.util.Queue) SortedMap(java.util.SortedMap) HashMap(java.util.HashMap) ContainerStorageStats(com.github.ambry.server.storagestats.ContainerStorageStats) HashMap(java.util.HashMap) Map(java.util.Map) ConcurrentNavigableMap(java.util.concurrent.ConcurrentNavigableMap) NavigableMap(java.util.NavigableMap) TreeMap(java.util.TreeMap) SortedMap(java.util.SortedMap)

Example 24 with ContainerStorageStats

use of com.github.ambry.server.storagestats.ContainerStorageStats in project ambry by linkedin.

the class StatsManagerTest method testStatsManagerDeleteTombstoneStats.

/**
 * Test to verify that the {@link StatsManager} is collecting delete tombstone stats.
 */
@Test
public void testStatsManagerDeleteTombstoneStats() {
    List<PartitionId> unreachablePartitions = Collections.emptyList();
    Map<Long, Map<Short, Map<Short, ContainerStorageStats>>> hostAccountStorageStatsMap = new HashMap<>();
    for (PartitionId partitionId : storeMap.keySet()) {
        statsManager.collectAndAggregateAccountStorageStats(hostAccountStorageStatsMap, partitionId, unreachablePartitions);
    }
    statsManager.updateAggregatedDeleteTombstoneStats();
    // verify aggregated delete tombstone stats
    StatsManager.AggregatedDeleteTombstoneStats deleteTombstoneStats = statsManager.getAggregatedDeleteTombstoneStats();
    Pair<Long, Long> expectedExpiredDeleteStats = storeDeleteTombstoneStats.get(EXPIRED_DELETE_TOMBSTONE);
    Pair<Long, Long> expectedPermanentDeleteStats = storeDeleteTombstoneStats.get(PERMANENT_DELETE_TOMBSTONE);
    assertEquals("Mismatch in expired delete count", storeMap.size() * expectedExpiredDeleteStats.getFirst(), deleteTombstoneStats.getExpiredDeleteTombstoneCount());
    assertEquals("Mismatch in expired delete size", storeMap.size() * expectedExpiredDeleteStats.getSecond(), deleteTombstoneStats.getExpiredDeleteTombstoneSize());
    assertEquals("Mismatch in permanent delete count", storeMap.size() * expectedPermanentDeleteStats.getFirst(), deleteTombstoneStats.getPermanentDeleteTombstoneCount());
    assertEquals("Mismatch in permanent delete size", storeMap.size() * expectedPermanentDeleteStats.getSecond(), deleteTombstoneStats.getPermanentDeleteTombstoneSize());
}
Also used : ContainerStorageStats(com.github.ambry.server.storagestats.ContainerStorageStats) HashMap(java.util.HashMap) MockPartitionId(com.github.ambry.clustermap.MockPartitionId) PartitionId(com.github.ambry.clustermap.PartitionId) Map(java.util.Map) HashMap(java.util.HashMap) MockClusterMap(com.github.ambry.clustermap.MockClusterMap) Test(org.junit.Test)

Example 25 with ContainerStorageStats

use of com.github.ambry.server.storagestats.ContainerStorageStats in project ambry by linkedin.

the class MySqlClusterAggregator method aggregateHostAccountStorageStatsWrappers.

/**
 * Aggregate all {@link HostAccountStorageStatsWrapper} to generate two {@link AggregatedAccountStorageStats}s. First
 * {@link AggregatedAccountStorageStats} is the sum of all {@link HostAccountStorageStatsWrapper}s. The second {@link AggregatedAccountStorageStats}
 * is the valid aggregated storage stats for all replicas of each partition.
 * @param statsWrappers A map from instance name to {@link HostAccountStorageStatsWrapper}.
 * @return A {@link Pair} of {@link AggregatedAccountStorageStats}.
 * @throws IOException
 */
Pair<AggregatedAccountStorageStats, AggregatedAccountStorageStats> aggregateHostAccountStorageStatsWrappers(Map<String, HostAccountStorageStatsWrapper> statsWrappers) throws IOException {
    Map<Long, Map<Short, Map<Short, ContainerStorageStats>>> combinedHostAccountStorageStatsMap = new HashMap<>();
    Map<Long, Map<Short, Map<Short, ContainerStorageStats>>> selectedHostAccountStorageStatsMap = new HashMap<>();
    Map<Long, Long> partitionTimestampMap = new HashMap<>();
    Map<Long, Long> partitionPhysicalStorageMap = new HashMap<>();
    for (Map.Entry<String, HostAccountStorageStatsWrapper> statsWrapperEntry : statsWrappers.entrySet()) {
        if (statsWrapperEntry.getValue() == null) {
            continue;
        }
        String instanceName = statsWrapperEntry.getKey();
        HostAccountStorageStatsWrapper hostAccountStorageStatsWrapper = statsWrapperEntry.getValue();
        HostAccountStorageStats hostAccountStorageStats = hostAccountStorageStatsWrapper.getStats();
        HostAccountStorageStats hostAccountStorageStatsCopy1 = new HostAccountStorageStats(hostAccountStorageStats);
        HostAccountStorageStats hostAccountStorageStatsCopy2 = new HostAccountStorageStats(hostAccountStorageStats);
        combineRawHostAccountStorageStatsMap(combinedHostAccountStorageStatsMap, hostAccountStorageStatsCopy1.getStorageStats());
        selectRawHostAccountStorageStatsMap(selectedHostAccountStorageStatsMap, hostAccountStorageStatsCopy2.getStorageStats(), partitionTimestampMap, partitionPhysicalStorageMap, hostAccountStorageStatsWrapper.getHeader().getTimestamp(), instanceName);
    }
    if (logger.isTraceEnabled()) {
        logger.trace("Combined raw HostAccountStorageStats {}", mapper.writeValueAsString(combinedHostAccountStorageStatsMap));
        logger.trace("Selected raw HostAccountStorageStats {}", mapper.writeValueAsString(selectedHostAccountStorageStatsMap));
    }
    AggregatedAccountStorageStats combinedAggregated = new AggregatedAccountStorageStats(aggregateHostAccountStorageStats(combinedHostAccountStorageStatsMap));
    AggregatedAccountStorageStats selectedAggregated = new AggregatedAccountStorageStats(aggregateHostAccountStorageStats(selectedHostAccountStorageStatsMap));
    if (logger.isTraceEnabled()) {
        logger.trace("Aggregated combined {}", mapper.writeValueAsString(combinedAggregated));
        logger.trace("Aggregated selected {}", mapper.writeValueAsString(selectedAggregated));
    }
    return new Pair<>(combinedAggregated, selectedAggregated);
}
Also used : HostAccountStorageStatsWrapper(com.github.ambry.server.HostAccountStorageStatsWrapper) HostAccountStorageStats(com.github.ambry.server.storagestats.HostAccountStorageStats) HashMap(java.util.HashMap) ContainerStorageStats(com.github.ambry.server.storagestats.ContainerStorageStats) AggregatedAccountStorageStats(com.github.ambry.server.storagestats.AggregatedAccountStorageStats) HashMap(java.util.HashMap) Map(java.util.Map) Pair(com.github.ambry.utils.Pair)

Aggregations

ContainerStorageStats (com.github.ambry.server.storagestats.ContainerStorageStats)39 HashMap (java.util.HashMap)36 Map (java.util.Map)36 Test (org.junit.Test)20 HostAccountStorageStats (com.github.ambry.server.storagestats.HostAccountStorageStats)16 HostAccountStorageStatsWrapper (com.github.ambry.server.HostAccountStorageStatsWrapper)12 StorageStatsUtilTest (com.github.ambry.server.StorageStatsUtilTest)12 StatsHeader (com.github.ambry.server.StatsHeader)10 AggregatedAccountStorageStats (com.github.ambry.server.storagestats.AggregatedAccountStorageStats)10 Pair (com.github.ambry.utils.Pair)8 ArrayList (java.util.ArrayList)7 LinkedHashMap (java.util.LinkedHashMap)7 HostPartitionClassStorageStats (com.github.ambry.server.storagestats.HostPartitionClassStorageStats)6 Utils (com.github.ambry.utils.Utils)6 MetricRegistry (com.codahale.metrics.MetricRegistry)5 AggregatedPartitionClassStorageStats (com.github.ambry.server.storagestats.AggregatedPartitionClassStorageStats)5 Collections (java.util.Collections)5 HashSet (java.util.HashSet)5 NavigableMap (java.util.NavigableMap)5 Set (java.util.Set)5