Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions plugins/storage/volume/linstor/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ public class LinstorPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver
private HostDao _hostDao;
@Inject private VMTemplateDao _vmTemplateDao;

private long volumeStatsLastUpdate = 0L;
private final Map<String, Long> volumeStatsLastUpdate = new HashMap<>();
private final Map<String, Pair<Long, Long>> volumeStats = new HashMap<>();

public LinstorPrimaryDataStoreDriverImpl()
Expand Down Expand Up @@ -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<ResourceWithVolumes> resources = api.viewResources(
Collections.emptyList(),
Collections.emptyList(),
Expand All @@ -1564,29 +1565,34 @@ private void fillVolumeStatsCache(DevelopersApi api) {
}
}

volumeStats.clear();
volumeStats.keySet().removeIf(key -> key.startsWith(linstorAddr));
for (Map.Entry<String, Long> entry : allocSizeMap.entrySet()) {
Long reserved = resSizeMap.getOrDefault(entry.getKey(), 0L);
Pair<Long, Long> 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());
}
}

@Override
public Pair<Long, Long> 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<Long, Long> 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;
}
}

Expand Down