/** Calculates and adds replica partition stats. */
  protected void addReplicaPartitionStats(
      LocalMapOnDemandCalculatedStats onDemandStats,
      String mapName,
      int partitionId,
      InternalPartition partition,
      InternalPartitionService partitionService,
      int backupCount,
      Address thisAddress) {
    long backupEntryCount = 0;
    long backupEntryMemoryCost = 0;

    for (int replica = 1; replica <= backupCount; replica++) {
      Address replicaAddress = getReplicaAddress(replica, partition, partitionService, backupCount);
      if (!isReplicaAvailable(replicaAddress, partitionService, backupCount)) {
        printWarning(partition, replica);
        continue;
      }
      if (isReplicaOnThisNode(replicaAddress, thisAddress)) {
        RecordStore recordStore = getRecordStoreOrNull(mapName, partitionId);
        if (hasRecords(recordStore)) {
          backupEntryMemoryCost += recordStore.getHeapCost();
          backupEntryCount += recordStore.size();
        }
      }
    }
    onDemandStats.incrementHeapCost(backupEntryMemoryCost);
    onDemandStats.incrementBackupEntryMemoryCost(backupEntryMemoryCost);
    onDemandStats.incrementBackupEntryCount(backupEntryCount);
  }
  public LocalMapStatsImpl createLocalMapStats(String mapName) {
    MapContainer mapContainer = mapServiceContext.getMapContainer(mapName);
    LocalMapStatsImpl stats = getLocalMapStatsImpl(mapName);
    if (!mapContainer.getMapConfig().isStatisticsEnabled()) {
      return stats;
    }
    int backupCount = mapContainer.getTotalBackupCount();
    Address thisAddress = clusterService.getThisAddress();

    LocalMapOnDemandCalculatedStats onDemandStats = new LocalMapOnDemandCalculatedStats();
    onDemandStats.setBackupCount(backupCount);

    addNearCacheStats(stats, onDemandStats, mapContainer);

    for (int partitionId = 0; partitionId < partitionService.getPartitionCount(); partitionId++) {
      InternalPartition partition = partitionService.getPartition(partitionId);
      Address owner = partition.getOwnerOrNull();
      if (owner == null) {
        // no-op because no owner is set yet. Therefore we don't know anything about the map
        continue;
      }

      if (owner.equals(thisAddress)) {
        addOwnerPartitionStats(stats, onDemandStats, mapName, partitionId);
      } else {
        addReplicaPartitionStats(
            onDemandStats,
            mapName,
            partitionId,
            partition,
            partitionService,
            backupCount,
            thisAddress);
      }
    }

    onDemandStats.copyValuesTo(stats);

    return stats;
  }
  /** Adds near cache stats. */
  protected void addNearCacheStats(
      LocalMapStatsImpl stats,
      LocalMapOnDemandCalculatedStats onDemandStats,
      MapContainer mapContainer) {
    if (!mapContainer.getMapConfig().isNearCacheEnabled()) {
      return;
    }
    NearCache nearCache = nearCacheProvider.getOrCreateNearCache(mapContainer.getName());
    NearCacheStats nearCacheStats = nearCache.getNearCacheStats();
    long nearCacheHeapCost = mapContainer.getNearCacheSizeEstimator().getSize();

    stats.setNearCacheStats(nearCacheStats);
    onDemandStats.incrementHeapCost(nearCacheHeapCost);
  }
  /** Calculates and adds owner partition stats. */
  protected void addOwnerPartitionStats(
      LocalMapStatsImpl stats,
      LocalMapOnDemandCalculatedStats onDemandStats,
      String mapName,
      int partitionId) {
    RecordStore recordStore = getRecordStoreOrNull(mapName, partitionId);
    if (!hasRecords(recordStore)) {
      return;
    }
    int lockedEntryCount = 0;
    long lastAccessTime = 0;
    long lastUpdateTime = 0;
    long hits = 0;

    Iterator<Record> iterator = recordStore.iterator();
    while (iterator.hasNext()) {
      Record record = iterator.next();
      Data key = record.getKey();

      hits += getHits(record);
      lockedEntryCount += isLocked(key, recordStore);
      lastAccessTime = Math.max(lastAccessTime, record.getLastAccessTime());
      lastUpdateTime = Math.max(lastUpdateTime, record.getLastUpdateTime());
    }

    onDemandStats.incrementLockedEntryCount(lockedEntryCount);
    onDemandStats.incrementHits(hits);
    onDemandStats.incrementDirtyEntryCount(
        recordStore.getMapDataStore().notFinishedOperationsCount());
    onDemandStats.incrementOwnedEntryMemoryCost(recordStore.getHeapCost());
    onDemandStats.incrementHeapCost(recordStore.getHeapCost());
    onDemandStats.incrementOwnedEntryCount(recordStore.size());

    stats.setLastAccessTime(lastAccessTime);
    stats.setLastUpdateTime(lastUpdateTime);
  }