diff --git a/plugins/storage/volume/linstor/CHANGELOG.md b/plugins/storage/volume/linstor/CHANGELOG.md index a96b7c75b2b5..c0991a9aa2b8 100644 --- a/plugins/storage/volume/linstor/CHANGELOG.md +++ b/plugins/storage/volume/linstor/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to Linstor CloudStack plugin will be documented in this file The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [2025-08-05] + +### Fixed + +- getVolumeStats wasn't correctly working if multiple Linstor clusters/primary storages are used. + ## [2025-07-01] ### Fixed diff --git a/plugins/storage/volume/linstor/src/main/java/org/apache/cloudstack/storage/datastore/driver/LinstorPrimaryDataStoreDriverImpl.java b/plugins/storage/volume/linstor/src/main/java/org/apache/cloudstack/storage/datastore/driver/LinstorPrimaryDataStoreDriverImpl.java index 71e1b5285067..0eefe0bcf9b0 100644 --- a/plugins/storage/volume/linstor/src/main/java/org/apache/cloudstack/storage/datastore/driver/LinstorPrimaryDataStoreDriverImpl.java +++ b/plugins/storage/volume/linstor/src/main/java/org/apache/cloudstack/storage/datastore/driver/LinstorPrimaryDataStoreDriverImpl.java @@ -135,7 +135,7 @@ public class LinstorPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver private HostDao _hostDao; @Inject private VMTemplateDao _vmTemplateDao; - private long volumeStatsLastUpdate = 0L; + private final Map volumeStatsLastUpdate = new HashMap<>(); private final Map> volumeStats = new HashMap<>(); public LinstorPrimaryDataStoreDriverImpl() @@ -1533,11 +1533,12 @@ public boolean canProvideVolumeStats() { /** * Updates the cache map containing current allocated size data. - * @param api Linstor Developers api object + * @param linstorAddr Linstor cluster api address */ - private void fillVolumeStatsCache(DevelopersApi api) { + private void fillVolumeStatsCache(String linstorAddr) { + final DevelopersApi api = LinstorUtil.getLinstorAPI(linstorAddr); try { - s_logger.trace("Start volume stats cache update"); + s_logger.trace("Start volume stats cache update for " + linstorAddr); List resources = api.viewResources( Collections.emptyList(), Collections.emptyList(), @@ -1564,14 +1565,14 @@ private void fillVolumeStatsCache(DevelopersApi api) { } } - volumeStats.clear(); + volumeStats.keySet().removeIf(key -> key.startsWith(linstorAddr)); for (Map.Entry entry : allocSizeMap.entrySet()) { Long reserved = resSizeMap.getOrDefault(entry.getKey(), 0L); Pair volStat = new Pair<>(entry.getValue(), reserved); - volumeStats.put(entry.getKey(), volStat); + volumeStats.put(linstorAddr + "/" + entry.getKey(), volStat); } - volumeStatsLastUpdate = System.currentTimeMillis(); - s_logger.trace("Done volume stats cache update: " + volumeStats.size()); + volumeStatsLastUpdate.put(linstorAddr, System.currentTimeMillis()); + s_logger.debug(String.format("Done volume stats cache update for %s: %d", linstorAddr, volumeStats.size())); } catch (ApiException e) { s_logger.error("Unable to fetch Linstor resources: " + e.getBestMessage()); } @@ -1579,14 +1580,19 @@ private void fillVolumeStatsCache(DevelopersApi api) { @Override public Pair getVolumeStats(StoragePool storagePool, String volumeId) { - final DevelopersApi api = LinstorUtil.getLinstorAPI(storagePool.getHostAddress()); + String linstorAddr = storagePool.getHostAddress(); synchronized (volumeStats) { - long invalidateCacheTime = volumeStatsLastUpdate + + long invalidateCacheTime = volumeStatsLastUpdate.getOrDefault(storagePool.getHostAddress(), 0L) + LinstorConfigurationManager.VolumeStatsCacheTime.value() * 1000; if (invalidateCacheTime < System.currentTimeMillis()) { - fillVolumeStatsCache(api); + fillVolumeStatsCache(storagePool.getHostAddress()); + } + String volumeKey = linstorAddr + "/" + LinstorUtil.RSC_PREFIX + volumeId; + Pair sizePair = volumeStats.get(volumeKey); + if (sizePair == null) { + s_logger.warn(String.format("Volumestats for %s not found in cache", volumeKey)); } - return volumeStats.get(LinstorUtil.RSC_PREFIX + volumeId); + return sizePair; } }