|
28 | 28 | import com.linbit.linstor.api.model.ResourceDefinitionCloneRequest; |
29 | 29 | import com.linbit.linstor.api.model.ResourceDefinitionCloneStarted; |
30 | 30 | import com.linbit.linstor.api.model.ResourceDefinitionCreate; |
31 | | - |
32 | 31 | import com.linbit.linstor.api.model.ResourceDefinitionModify; |
33 | 32 | import com.linbit.linstor.api.model.ResourceGroup; |
34 | 33 | import com.linbit.linstor.api.model.ResourceGroupSpawn; |
35 | 34 | import com.linbit.linstor.api.model.ResourceMakeAvailable; |
| 35 | +import com.linbit.linstor.api.model.ResourceWithVolumes; |
36 | 36 | import com.linbit.linstor.api.model.Snapshot; |
37 | 37 | import com.linbit.linstor.api.model.SnapshotRestore; |
38 | 38 | import com.linbit.linstor.api.model.VolumeDefinition; |
@@ -132,6 +132,9 @@ public class LinstorPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver |
132 | 132 | @Inject |
133 | 133 | private HostDao _hostDao; |
134 | 134 |
|
| 135 | + private long volumeStatsLastUpdate = 0L; |
| 136 | + private final Map<String, Pair<Long, Long>> volumeStats = new HashMap<>(); |
| 137 | + |
135 | 138 | public LinstorPrimaryDataStoreDriverImpl() |
136 | 139 | { |
137 | 140 | } |
@@ -401,9 +404,9 @@ private void applyQoSSettings(StoragePoolVO storagePool, DevelopersApi api, Stri |
401 | 404 | } |
402 | 405 | } |
403 | 406 |
|
404 | | - private String getRscGrp(StoragePoolVO storagePoolVO) { |
405 | | - return storagePoolVO.getUserInfo() != null && !storagePoolVO.getUserInfo().isEmpty() ? |
406 | | - storagePoolVO.getUserInfo() : "DfltRscGrp"; |
| 407 | + private String getRscGrp(StoragePool storagePool) { |
| 408 | + return storagePool.getUserInfo() != null && !storagePool.getUserInfo().isEmpty() ? |
| 409 | + storagePool.getUserInfo() : "DfltRscGrp"; |
407 | 410 | } |
408 | 411 |
|
409 | 412 | /** |
@@ -1504,22 +1507,77 @@ public void takeSnapshot(SnapshotInfo snapshotInfo, AsyncCompletionCallback<Crea |
1504 | 1507 |
|
1505 | 1508 | @Override |
1506 | 1509 | public boolean canProvideStorageStats() { |
1507 | | - return false; |
| 1510 | + return true; |
1508 | 1511 | } |
1509 | 1512 |
|
1510 | 1513 | @Override |
1511 | 1514 | public Pair<Long, Long> getStorageStats(StoragePool storagePool) { |
1512 | | - return null; |
| 1515 | + s_logger.debug(String.format("Requesting storage stats: %s", storagePool)); |
| 1516 | + return LinstorUtil.getStorageStats(storagePool.getHostAddress(), getRscGrp(storagePool)); |
1513 | 1517 | } |
1514 | 1518 |
|
1515 | 1519 | @Override |
1516 | 1520 | public boolean canProvideVolumeStats() { |
1517 | | - return false; |
| 1521 | + return LinstorConfigurationManager.VolumeStatsCacheTime.value() > 0; |
| 1522 | + } |
| 1523 | + |
| 1524 | + /** |
| 1525 | + * Updates the cache map containing current allocated size data. |
| 1526 | + * @param api Linstor Developers api object |
| 1527 | + */ |
| 1528 | + private void fillVolumeStatsCache(DevelopersApi api) { |
| 1529 | + try { |
| 1530 | + s_logger.trace("Start volume stats cache update"); |
| 1531 | + List<ResourceWithVolumes> resources = api.viewResources( |
| 1532 | + Collections.emptyList(), |
| 1533 | + Collections.emptyList(), |
| 1534 | + Collections.emptyList(), |
| 1535 | + null, |
| 1536 | + null, |
| 1537 | + null); |
| 1538 | + |
| 1539 | + List<ResourceDefinition> rscDfns = api.resourceDefinitionList( |
| 1540 | + Collections.emptyList(), true, null, null, null); |
| 1541 | + |
| 1542 | + HashMap<String, Long> resSizeMap = new HashMap<>(); |
| 1543 | + for (ResourceDefinition rscDfn : rscDfns) { |
| 1544 | + if (CollectionUtils.isNotEmpty(rscDfn.getVolumeDefinitions())) { |
| 1545 | + resSizeMap.put(rscDfn.getName(), rscDfn.getVolumeDefinitions().get(0).getSizeKib() * 1024); |
| 1546 | + } |
| 1547 | + } |
| 1548 | + |
| 1549 | + HashMap<String, Long> allocSizeMap = new HashMap<>(); |
| 1550 | + for (ResourceWithVolumes rsc : resources) { |
| 1551 | + if (!LinstorUtil.isRscDiskless(rsc) && !rsc.getVolumes().isEmpty()) { |
| 1552 | + long allocatedBytes = allocSizeMap.getOrDefault(rsc.getName(), 0L); |
| 1553 | + allocSizeMap.put(rsc.getName(), Math.max(allocatedBytes, rsc.getVolumes().get(0).getAllocatedSizeKib() * 1024)); |
| 1554 | + } |
| 1555 | + } |
| 1556 | + |
| 1557 | + volumeStats.clear(); |
| 1558 | + for (Map.Entry<String, Long> entry : allocSizeMap.entrySet()) { |
| 1559 | + Long reserved = resSizeMap.getOrDefault(entry.getKey(), 0L); |
| 1560 | + Pair<Long, Long> volStat = new Pair<>(entry.getValue(), reserved); |
| 1561 | + volumeStats.put(entry.getKey(), volStat); |
| 1562 | + } |
| 1563 | + volumeStatsLastUpdate = System.currentTimeMillis(); |
| 1564 | + s_logger.trace("Done volume stats cache update: " + volumeStats.size()); |
| 1565 | + } catch (ApiException e) { |
| 1566 | + s_logger.error("Unable to fetch Linstor resources: " + e.getBestMessage()); |
| 1567 | + } |
1518 | 1568 | } |
1519 | 1569 |
|
1520 | 1570 | @Override |
1521 | 1571 | public Pair<Long, Long> getVolumeStats(StoragePool storagePool, String volumeId) { |
1522 | | - return null; |
| 1572 | + final DevelopersApi api = LinstorUtil.getLinstorAPI(storagePool.getHostAddress()); |
| 1573 | + synchronized (volumeStats) { |
| 1574 | + long invalidateCacheTime = volumeStatsLastUpdate + |
| 1575 | + LinstorConfigurationManager.VolumeStatsCacheTime.value() * 1000; |
| 1576 | + if (invalidateCacheTime < System.currentTimeMillis()) { |
| 1577 | + fillVolumeStatsCache(api); |
| 1578 | + } |
| 1579 | + return volumeStats.get(LinstorUtil.RSC_PREFIX + volumeId); |
| 1580 | + } |
1523 | 1581 | } |
1524 | 1582 |
|
1525 | 1583 | @Override |
|
0 commit comments