diff --git a/src/components/DiskStateProgressBar/DiskStateProgressBar.tsx b/src/components/DiskStateProgressBar/DiskStateProgressBar.tsx
index c4cffc191c..a5e806de34 100644
--- a/src/components/DiskStateProgressBar/DiskStateProgressBar.tsx
+++ b/src/components/DiskStateProgressBar/DiskStateProgressBar.tsx
@@ -44,7 +44,11 @@ export function DiskStateProgressBar({
return
;
}
- const fillWidth = inverted ? 100 - diskAllocatedPercent : diskAllocatedPercent;
+ // diskAllocatedPercent could be more than 100
+ let fillWidth = Math.min(diskAllocatedPercent, 100);
+ if (inverted) {
+ fillWidth = Math.max(100 - diskAllocatedPercent, 0);
+ }
if (diskAllocatedPercent >= 0) {
return ;
diff --git a/src/components/VDiskInfo/VDiskInfo.tsx b/src/components/VDiskInfo/VDiskInfo.tsx
index 27cccc90aa..d2017ecebe 100644
--- a/src/components/VDiskInfo/VDiskInfo.tsx
+++ b/src/components/VDiskInfo/VDiskInfo.tsx
@@ -49,6 +49,7 @@ export function VDiskInfo({
const {
AllocatedSize,
+ SizeLimit,
DiskSpace,
FrontQueues,
Guid,
@@ -60,7 +61,6 @@ export function VDiskInfo({
VDiskSlotId,
Kind,
SatisfactionRank,
- AvailableSize,
HasUnreadableBlobs,
IncarnationGuid,
InstanceGuid,
@@ -83,13 +83,14 @@ export function VDiskInfo({
value: VDiskState,
});
}
- if (Number(AllocatedSize) >= 0 && Number(AvailableSize) >= 0) {
+
+ if (Number(AllocatedSize) >= 0 && Number(SizeLimit) >= 0) {
leftColumn.push({
label: vDiskInfoKeyset('size'),
value: (
diff --git a/src/store/reducers/pdisk/__tests__/preparePDiskDataResponse.test.ts b/src/store/reducers/pdisk/__tests__/preparePDiskDataResponse.test.ts
index beb1b6f9d7..2ca4839a62 100644
--- a/src/store/reducers/pdisk/__tests__/preparePDiskDataResponse.test.ts
+++ b/src/store/reducers/pdisk/__tests__/preparePDiskDataResponse.test.ts
@@ -255,4 +255,38 @@ describe('preparePDiskDataResponse', () => {
1,
);
});
+
+ test('Should use used size as total for VDisk slot when used size exceeds size limit', () => {
+ const dataWithExceededVDiskUsage: TPDiskInfoResponse = {
+ ...rawData,
+ Whiteboard: {
+ ...rawData.Whiteboard,
+ PDisk: {
+ ...rawData.Whiteboard?.PDisk,
+ EnforcedDynamicSlotSize: '15000000000', // 15GB slot size
+ },
+ VDisks: [
+ {
+ ...rawData.Whiteboard?.VDisks?.[0],
+ AllocatedSize: '20000000000', // 20GB used (exceeds 15GB slot size)
+ AvailableSize: '0', // 0 available, so slot size should be used as limit
+ },
+ ],
+ },
+ BSC: {
+ ...rawData.BSC,
+ PDisk: {
+ ...rawData.BSC?.PDisk,
+ EnforcedDynamicSlotSize: '15000000000', // 15GB slot size
+ },
+ },
+ };
+ const preparedData = preparePDiskDataResponse([dataWithExceededVDiskUsage, {}]);
+
+ const vDiskSlot = preparedData.SlotItems?.find((slot) => slot.SlotType === 'vDisk');
+
+ expect(vDiskSlot?.Used).toEqual(20_000_000_000); // 20GB used
+ // Since used (20GB) > sizeLimit (15GB), total should be set to used size
+ expect(vDiskSlot?.Total).toEqual(20_000_000_000); // Total equals used when used exceeds limit
+ });
});
diff --git a/src/store/reducers/pdisk/utils.ts b/src/store/reducers/pdisk/utils.ts
index e0daa5d7c8..fc65a55a2c 100644
--- a/src/store/reducers/pdisk/utils.ts
+++ b/src/store/reducers/pdisk/utils.ts
@@ -70,13 +70,22 @@ export function preparePDiskDataResponse([pdiskResponse = {}, nodeResponse]: [
// VDisks with their full statuses can be seen in popup on hover, in Storage table and on vdisks pages
const slotSeverity = getSpaceSeverity(preparedVDisk.AllocatedPercent);
+ const used = Number(preparedVDisk.AllocatedSize);
+ let total = Number(preparedVDisk.SizeLimit);
+
+ // In case used size is more than limit
+ // use used size as total to show correct slot relative size
+ if (used > total) {
+ total = used;
+ }
+
return {
SlotType: 'vDisk',
Id: preparedVDisk.VDiskId?.GroupID,
Title: preparedVDisk.StoragePoolName,
Severity: slotSeverity,
- Used: Number(preparedVDisk.AllocatedSize),
- Total: Number(preparedVDisk.TotalSize),
+ Used: used,
+ Total: total,
UsagePercent: preparedVDisk.AllocatedPercent,
SlotData: preparedVDisk,
diff --git a/src/store/reducers/storage/__tests__/prepareGroupsDisks.test.ts b/src/store/reducers/storage/__tests__/prepareGroupsDisks.test.ts
index a5bd6e75a5..1d79ffac43 100644
--- a/src/store/reducers/storage/__tests__/prepareGroupsDisks.test.ts
+++ b/src/store/reducers/storage/__tests__/prepareGroupsDisks.test.ts
@@ -91,7 +91,7 @@ describe('prepareGroupsVDisk', () => {
AllocatedSize: 30943477760,
AvailableSize: 234461593600,
- TotalSize: 265405071360,
+ SizeLimit: 265405071360,
AllocatedPercent: 11,
Donors: undefined,
@@ -134,7 +134,7 @@ describe('prepareGroupsVDisk', () => {
AllocatedSize: 30943477760,
AvailableSize: 234461593600,
- TotalSize: 265405071360,
+ SizeLimit: 265405071360,
AllocatedPercent: 11,
PDisk: {
@@ -236,7 +236,7 @@ describe('prepareGroupsVDisk', () => {
AllocatedSize: 30943477760,
AvailableSize: 234461593600,
- TotalSize: 265405071360,
+ SizeLimit: 265405071360,
AllocatedPercent: 11,
Donors: undefined,
diff --git a/src/store/reducers/storage/prepareGroupsDisks.ts b/src/store/reducers/storage/prepareGroupsDisks.ts
index d49875a3e8..6ff584fdaf 100644
--- a/src/store/reducers/storage/prepareGroupsDisks.ts
+++ b/src/store/reducers/storage/prepareGroupsDisks.ts
@@ -25,8 +25,9 @@ export function prepareGroupsVDisk(data: TStorageVDisk = {}): PreparedVDisk {
const Severity = calculateVDiskSeverity(mergedVDiskData);
const vDiskSizeFields = prepareVDiskSizeFields({
- AvailableSize: mergedVDiskData.AvailableSize ?? PDisk?.AvailableSize,
+ AvailableSize: mergedVDiskData.AvailableSize,
AllocatedSize: mergedVDiskData.AllocatedSize,
+ SlotSize: PDisk?.SlotSize,
});
const preparedDonors = bscVDisk.Donors?.map((donor) => {
diff --git a/src/store/reducers/vdisk/utils.ts b/src/store/reducers/vdisk/utils.ts
index 09a8ef696a..50067aa17a 100644
--- a/src/store/reducers/vdisk/utils.ts
+++ b/src/store/reducers/vdisk/utils.ts
@@ -1,10 +1,7 @@
import type {StorageGroupsResponse} from '../../../types/api/storage';
import type {TEvSystemStateResponse} from '../../../types/api/systemState';
-import {
- prepareWhiteboardPDiskData,
- prepareWhiteboardVDiskData,
-} from '../../../utils/disks/prepareDisks';
import {prepareNodeSystemState} from '../../../utils/nodes';
+import {prepareGroupsVDisk} from '../storage/prepareGroupsDisks';
import type {VDiskData} from './types';
@@ -18,21 +15,20 @@ export function prepareVDiskDataResponse(
const rawVDisk = storageGroupResponse?.StorageGroups?.[0].VDisks?.find(
({VDiskId}) => VDiskId === vDiskId,
);
- const preparedVDisk = prepareWhiteboardVDiskData(rawVDisk?.Whiteboard);
- const rawPDisk = rawVDisk?.PDisk?.Whiteboard;
- const preparedPDisk = prepareWhiteboardPDiskData(rawPDisk);
+ const preparedVDisk = prepareGroupsVDisk(rawVDisk);
+ const preparedPDisk = preparedVDisk.PDisk;
const rawNode = nodeResponse?.SystemStateInfo?.[0];
const preparedNode = prepareNodeSystemState(rawNode);
- const NodeId = preparedVDisk.NodeId ?? preparedPDisk.NodeId ?? preparedNode.NodeId;
+ const NodeId = preparedVDisk.NodeId ?? preparedPDisk?.NodeId ?? preparedNode.NodeId;
const NodeHost = preparedNode.Host;
const NodeType = preparedNode.Roles?.[0];
const NodeDC = preparedNode.DC;
- const PDiskId = preparedVDisk.PDiskId ?? preparedPDisk.PDiskId;
- const PDiskType = preparedPDisk.Type;
+ const PDiskId = preparedVDisk.PDiskId ?? preparedPDisk?.PDiskId;
+ const PDiskType = preparedPDisk?.Type;
return {
...preparedVDisk,
diff --git a/src/utils/disks/__test__/prepareDisks.test.ts b/src/utils/disks/__test__/prepareDisks.test.ts
index 85a9df4266..22dd375f0f 100644
--- a/src/utils/disks/__test__/prepareDisks.test.ts
+++ b/src/utils/disks/__test__/prepareDisks.test.ts
@@ -90,7 +90,7 @@ describe('prepareWhiteboardVDiskData', () => {
AvailableSize: 188523479040,
AllocatedSize: 8996782080,
- TotalSize: 197520261120,
+ SizeLimit: 197520261120,
AllocatedPercent: 4,
};
@@ -180,29 +180,92 @@ describe('prepareWhiteboardPDiskData', () => {
});
describe('prepareVDiskSizeFields', () => {
- test('Should prepare VDisk size fields', () => {
+ test('Should prepare VDisk size fields with allocated + available as size limit', () => {
expect(
prepareVDiskSizeFields({
AvailableSize: '400',
AllocatedSize: '100',
+ SlotSize: '500',
}),
).toEqual({
AvailableSize: 400,
AllocatedSize: 100,
- TotalSize: 500,
- AllocatedPercent: 20,
+ SizeLimit: 500, // allocated (100) + available (400) = 500
+ AllocatedPercent: 20, // 100 / 500 * 100 = 20%
});
});
- test('Returns NaN if on undefined data', () => {
+
+ test('Should use SlotSize as size limit when AvailableSize is 0', () => {
+ expect(
+ prepareVDiskSizeFields({
+ AvailableSize: '0',
+ AllocatedSize: '500',
+ SlotSize: '500',
+ }),
+ ).toEqual({
+ AvailableSize: 0,
+ AllocatedSize: 500,
+ SizeLimit: 500, // SlotSize is used when available is 0
+ AllocatedPercent: 100, // 500 / 500 * 100 = 100%
+ });
+ });
+
+ test('Should use SlotSize as size limit when AvailableSize is undefined', () => {
+ expect(
+ prepareVDiskSizeFields({
+ AvailableSize: undefined,
+ AllocatedSize: '300',
+ SlotSize: '500',
+ }),
+ ).toEqual({
+ AvailableSize: 0,
+ AllocatedSize: 300,
+ SizeLimit: 500, // SlotSize is used when available is undefined
+ AllocatedPercent: 60, // 300 / 500 * 100 = 60%
+ });
+ });
+
+ test('Should use allocated when SlotSize is undefined and available is 0', () => {
+ expect(
+ prepareVDiskSizeFields({
+ AvailableSize: '0',
+ AllocatedSize: '500',
+ SlotSize: undefined,
+ }),
+ ).toEqual({
+ AvailableSize: 0,
+ AllocatedSize: 500,
+ SizeLimit: 500, // allocated (500)
+ AllocatedPercent: 100, // 500 / 500 * 100 = 100%
+ });
+ });
+
+ test('Should handle case when used size exceeds slot size', () => {
+ expect(
+ prepareVDiskSizeFields({
+ AvailableSize: '0',
+ AllocatedSize: '800',
+ SlotSize: '500',
+ }),
+ ).toEqual({
+ AvailableSize: 0,
+ AllocatedSize: 800,
+ SizeLimit: 500, // SlotSize is used as limit
+ AllocatedPercent: 160, // 800 / 500 * 100 = 160%
+ });
+ });
+
+ test('Should return NaN for undefined data', () => {
expect(
prepareVDiskSizeFields({
AvailableSize: undefined,
AllocatedSize: undefined,
+ SlotSize: undefined,
}),
).toEqual({
- AvailableSize: NaN,
+ AvailableSize: 0,
AllocatedSize: NaN,
- TotalSize: NaN,
+ SizeLimit: NaN,
AllocatedPercent: NaN,
});
});
diff --git a/src/utils/disks/prepareDisks.ts b/src/utils/disks/prepareDisks.ts
index efe4d24ccc..6770b0d80c 100644
--- a/src/utils/disks/prepareDisks.ts
+++ b/src/utils/disks/prepareDisks.ts
@@ -56,8 +56,9 @@ export function prepareWhiteboardVDiskData(
const actualPDiskId = PDiskId ?? preparedPDisk?.PDiskId;
const vDiskSizeFields = prepareVDiskSizeFields({
- AvailableSize: AvailableSize ?? PDisk?.AvailableSize,
+ AvailableSize: AvailableSize,
AllocatedSize: AllocatedSize,
+ SlotSize: PDisk?.EnforcedDynamicSlotSize,
});
const Severity = calculateVDiskSeverity(vDiskState);
@@ -145,19 +146,30 @@ export function prepareWhiteboardPDiskData(pdiskState: TPDiskStateInfo = {}): Pr
export function prepareVDiskSizeFields({
AvailableSize,
AllocatedSize,
+ SlotSize,
}: {
AvailableSize: string | number | undefined;
AllocatedSize: string | number | undefined;
+ SlotSize: string | number | undefined;
}) {
- const available = Number(AvailableSize);
+ const available = Number(AvailableSize ?? 0);
+ // Unlike available, allocated is displayed in UI, it is incorrect to fallback it to 0
const allocated = Number(AllocatedSize);
- const total = allocated + available;
- const allocatedPercent = Math.floor((allocated * 100) / total);
+ const slotSize = Number(SlotSize);
+
+ let sizeLimit = allocated + available;
+
+ // If no available size or available size is 0, slot size should be used as limit
+ if (!available && slotSize) {
+ sizeLimit = slotSize;
+ }
+
+ const allocatedPercent = sizeLimit > 0 ? Math.floor((allocated * 100) / sizeLimit) : NaN;
return {
AvailableSize: available,
AllocatedSize: allocated,
- TotalSize: total,
+ SizeLimit: sizeLimit,
AllocatedPercent: allocatedPercent,
};
}
diff --git a/src/utils/disks/types.ts b/src/utils/disks/types.ts
index 45371819fd..28b4a8fbe3 100644
--- a/src/utils/disks/types.ts
+++ b/src/utils/disks/types.ts
@@ -28,9 +28,9 @@ export interface PreparedVDisk
StringifiedId?: string;
AvailableSize?: number;
- TotalSize?: number;
AllocatedSize?: number;
AllocatedPercent?: number;
+ SizeLimit?: number;
Donors?: PreparedVDisk[];
}