Skip to content

Commit 6cfa524

Browse files
Merge pull request #4168 from RedisInsight/be/feature/RIVS-31_Logical_databases
2 parents f368fb3 + 0c19906 commit 6cfa524

File tree

7 files changed

+71
-20
lines changed

7 files changed

+71
-20
lines changed

redisinsight/api/src/__mocks__/databases.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
import { CloudDatabaseDetailsEntity } from 'src/modules/cloud/database/entities/cloud-database-details.entity';
1818
import { mockCloudDatabaseDetails, mockCloudDatabaseDetailsEntity } from 'src/__mocks__/cloud-database';
1919
import { mockRedisClientListResult } from 'src/__mocks__/database-info';
20+
import { DatabaseOverviewKeyspace } from 'src/modules/database/constants/overview';
2021

2122
export const mockDatabaseId = 'a77b23c1-7816-4ea4-b61f-d37795a0f805-db-id';
2223

@@ -220,6 +221,8 @@ export const mockDatabaseOverview: DatabaseOverview = {
220221
cpuUsagePercentage: null,
221222
};
222223

224+
export const mockDatabaseOverviewCurrentKeyspace = DatabaseOverviewKeyspace.Current;
225+
223226
export const mockRedisServerInfoDto = {
224227
redis_version: '7.0.5',
225228
redis_mode: 'standalone',
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export enum DatabaseOverviewKeyspace {
2+
Full = 'full',
3+
Current = 'current',
4+
}

redisinsight/api/src/modules/database/database-info.controller.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { ApiTags } from '@nestjs/swagger';
1+
import { ApiQuery, ApiTags } from '@nestjs/swagger';
22
import {
3-
Controller, Get, Param, UseInterceptors, UsePipes, ValidationPipe,
3+
Controller, Get, Param, Query, UseInterceptors, UsePipes, ValidationPipe,
44
} from '@nestjs/common';
55
import { ApiEndpoint } from 'src/decorators/api-endpoint.decorator';
66
import { TimeoutInterceptor } from 'src/common/interceptors/timeout.interceptor';
@@ -10,6 +10,7 @@ import { RedisDatabaseInfoResponse } from 'src/modules/database/dto/redis-info.d
1010
import { ClientMetadata, DatabaseIndex } from 'src/common/models';
1111
import { ClientMetadataParam } from 'src/common/decorators';
1212
import { DbIndexValidationPipe } from 'src/common/pipes';
13+
import { DatabaseOverviewKeyspace } from './constants/overview';
1314

1415
@ApiTags('Database Instances')
1516
@Controller('databases')
@@ -54,13 +55,19 @@ export class DatabaseInfoController {
5455
},
5556
],
5657
})
58+
@ApiQuery({
59+
name: 'keyspace',
60+
required: false,
61+
enum: DatabaseOverviewKeyspace,
62+
})
5763
async getDatabaseOverview(
5864
@ClientMetadataParam({
5965
databaseIdParam: 'id',
6066
ignoreDbIndex: false, // do not ignore db index to calculate current (selected) keys in db
6167
}) clientMetadata: ClientMetadata,
68+
@Query() { keyspace = DatabaseOverviewKeyspace.Current }: { keyspace: DatabaseOverviewKeyspace },
6269
): Promise<DatabaseOverview> {
63-
return this.databaseInfoService.getOverview(clientMetadata);
70+
return this.databaseInfoService.getOverview(clientMetadata, keyspace);
6471
}
6572

6673
@Get(':id/db/:index')

redisinsight/api/src/modules/database/database-info.service.spec.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
mockDatabaseInfoProvider,
66
mockDatabaseOverview,
77
mockDatabaseOverviewProvider,
8+
mockDatabaseOverviewCurrentKeyspace,
89
mockDatabaseRecommendationService,
910
mockDatabaseService,
1011
mockDBSize,
@@ -71,7 +72,9 @@ describe('DatabaseInfoService', () => {
7172

7273
describe('getOverview', () => {
7374
it('should create client and get overview', async () => {
74-
expect(await service.getOverview(mockCommonClientMetadata)).toEqual(mockDatabaseOverview);
75+
expect(
76+
await service.getOverview(mockCommonClientMetadata, mockDatabaseOverviewCurrentKeyspace),
77+
).toEqual(mockDatabaseOverview);
7578
});
7679
});
7780

redisinsight/api/src/modules/database/database-info.service.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { DatabaseClientFactory } from 'src/modules/database/providers/database.c
99
import { RedisClient } from 'src/modules/redis/client';
1010
import { DatabaseInfoProvider } from 'src/modules/database/providers/database-info.provider';
1111
import { DatabaseService } from './database.service';
12+
import { DatabaseOverviewKeyspace } from './constants/overview';
1213

1314
@Injectable()
1415
export class DatabaseInfoService {
@@ -38,16 +39,20 @@ export class DatabaseInfoService {
3839
* Get redis database overview
3940
*
4041
* @param clientMetadata
42+
* @param keyspace
4143
*/
42-
public async getOverview(clientMetadata: ClientMetadata): Promise<DatabaseOverview> {
44+
public async getOverview(
45+
clientMetadata: ClientMetadata,
46+
keyspace: DatabaseOverviewKeyspace,
47+
): Promise<DatabaseOverview> {
4348
this.logger.log(`Getting database overview for: ${clientMetadata.databaseId}`);
4449

4550
const client: RedisClient = await this.databaseClientFactory.getOrCreateClient({
4651
...clientMetadata,
4752
db: undefined, // connect to default db index
4853
});
4954

50-
return this.databaseOverviewProvider.getOverview(clientMetadata, client);
55+
return this.databaseOverviewProvider.getOverview(clientMetadata, client, keyspace);
5156
}
5257

5358
/**

redisinsight/api/src/modules/database/providers/database-overview.provider.spec.ts

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
import { DatabaseOverview } from 'src/modules/database/models/database-overview';
1010
import { DatabaseOverviewProvider } from 'src/modules/database/providers/database-overview.provider';
1111
import * as Utils from 'src/modules/redis/utils/keys.util';
12+
import { DatabaseOverviewKeyspace } from 'src/modules/database/constants/overview';
1213

1314
const mockServerInfo = {
1415
redis_version: '6.2.4',
@@ -32,6 +33,7 @@ const mockCpu = {
3233
const standaloneClientsInfo = {
3334
connected_clients: '1',
3435
};
36+
const mockCurrentKeyspace = DatabaseOverviewKeyspace.Current;
3537
const mockKeyspace = {
3638
db0: 'keys=1,expires=0,avg_ttl=0',
3739
db1: 'keys=0,expires=0,avg_ttl=0',
@@ -93,7 +95,7 @@ describe('OverviewService', () => {
9395
.calledWith(['info'], { replyEncoding: 'utf8' })
9496
.mockResolvedValue(mockStandaloneRedisInfoReply);
9597

96-
const result = await service.getOverview(mockClientMetadata, standaloneClient);
98+
const result = await service.getOverview(mockClientMetadata, standaloneClient, mockCurrentKeyspace);
9799

98100
expect(result).toEqual({
99101
...mockDatabaseOverview,
@@ -116,7 +118,7 @@ describe('OverviewService', () => {
116118
},
117119
});
118120

119-
expect(await service.getOverview(mockClientMetadata, standaloneClient)).toEqual({
121+
expect(await service.getOverview(mockClientMetadata, standaloneClient, mockCurrentKeyspace)).toEqual({
120122
...mockDatabaseOverview,
121123
totalKeys: 0,
122124
totalKeysPerDb: undefined,
@@ -133,7 +135,7 @@ describe('OverviewService', () => {
133135
},
134136
});
135137

136-
expect(await service.getOverview(mockClientMetadata, standaloneClient)).toEqual({
138+
expect(await service.getOverview(mockClientMetadata, standaloneClient, mockCurrentKeyspace)).toEqual({
137139
...mockDatabaseOverview,
138140
totalKeys: 3,
139141
totalKeysPerDb: undefined,
@@ -150,7 +152,7 @@ describe('OverviewService', () => {
150152
clients: undefined,
151153
});
152154

153-
expect(await service.getOverview(mockClientMetadata, standaloneClient)).toEqual({
155+
expect(await service.getOverview(mockClientMetadata, standaloneClient, mockCurrentKeyspace)).toEqual({
154156
...mockDatabaseOverview,
155157
totalKeys: undefined,
156158
usedMemory: undefined,
@@ -173,11 +175,11 @@ describe('OverviewService', () => {
173175
},
174176
});
175177

176-
expect(await service.getOverview(mockClientMetadata, standaloneClient)).toEqual({
178+
expect(await service.getOverview(mockClientMetadata, standaloneClient, mockCurrentKeyspace)).toEqual({
177179
...mockDatabaseOverview,
178180
});
179181

180-
expect(await service.getOverview(mockClientMetadata, standaloneClient)).toEqual({
182+
expect(await service.getOverview(mockClientMetadata, standaloneClient, mockCurrentKeyspace)).toEqual({
181183
...mockDatabaseOverview,
182184
cpuUsagePercentage: 50,
183185
});
@@ -197,11 +199,11 @@ describe('OverviewService', () => {
197199
},
198200
});
199201

200-
expect(await service.getOverview(mockClientMetadata, standaloneClient)).toEqual({
202+
expect(await service.getOverview(mockClientMetadata, standaloneClient, mockCurrentKeyspace)).toEqual({
201203
...mockDatabaseOverview,
202204
});
203205

204-
expect(await service.getOverview(mockClientMetadata, standaloneClient)).toEqual({
206+
expect(await service.getOverview(mockClientMetadata, standaloneClient, mockCurrentKeyspace)).toEqual({
205207
...mockDatabaseOverview,
206208
cpuUsagePercentage: 100,
207209
});
@@ -220,11 +222,23 @@ describe('OverviewService', () => {
220222
},
221223
});
222224

223-
expect(await service.getOverview(mockClientMetadata, standaloneClient)).toEqual({
225+
expect(await service.getOverview(mockClientMetadata, standaloneClient, mockCurrentKeyspace)).toEqual({
224226
...mockDatabaseOverview,
225227
cpuUsagePercentage: undefined,
226228
});
227229
});
230+
it('should full data of keyspace if query keyspace = "full" ', async () => {
231+
spyGetNodeInfo.mockResolvedValueOnce(mockNodeInfo);
232+
233+
expect(await service.getOverview(mockClientMetadata, standaloneClient, DatabaseOverviewKeyspace.Full)).toEqual({
234+
...mockDatabaseOverview,
235+
totalKeysPerDb: {
236+
db0: 1,
237+
db1: 0,
238+
db2: 1,
239+
},
240+
});
241+
});
228242
});
229243
describe('Cluster', () => {
230244
it('Should calculate overview and ignore replica where needed', async () => {
@@ -260,7 +274,7 @@ describe('OverviewService', () => {
260274
replication: { role: 'slave' },
261275
});
262276

263-
expect(await service.getOverview(mockClientMetadata, clusterClient)).toEqual({
277+
expect(await service.getOverview(mockClientMetadata, clusterClient, mockCurrentKeyspace)).toEqual({
264278
...mockDatabaseOverview,
265279
connectedClients: 1,
266280
totalKeys: 6,
@@ -315,7 +329,7 @@ describe('OverviewService', () => {
315329
cpu: { ...mockNodeInfo.cpu, used_cpu_sys: '1.5', used_cpu_user: '1.5' },
316330
});
317331

318-
expect(await service.getOverview(mockClientMetadata, clusterClient)).toEqual({
332+
expect(await service.getOverview(mockClientMetadata, clusterClient, mockCurrentKeyspace)).toEqual({
319333
...mockDatabaseOverview,
320334
connectedClients: 1,
321335
totalKeys: 6,

redisinsight/api/src/modules/database/providers/database-overview.provider.ts

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { getTotalKeys, convertMultilineReplyToObject } from 'src/modules/redis/u
1515
import { DatabaseOverview } from 'src/modules/database/models/database-overview';
1616
import { ClientMetadata } from 'src/common/models';
1717
import { RedisClient, RedisClientConnectionType, RedisClientNodeRole } from 'src/modules/redis/client';
18+
import { DatabaseOverviewKeyspace } from '../constants/overview';
1819

1920
@Injectable()
2021
export class DatabaseOverviewProvider {
@@ -24,10 +25,12 @@ export class DatabaseOverviewProvider {
2425
* Calculates redis database metrics based on connection type (eg Cluster or Standalone)
2526
* @param clientMetadata
2627
* @param client
28+
* @param keyspace
2729
*/
2830
async getOverview(
2931
clientMetadata: ClientMetadata,
3032
client: RedisClient,
33+
keyspace: DatabaseOverviewKeyspace,
3134
): Promise<DatabaseOverview> {
3235
let nodesInfo = [];
3336
let totalKeys;
@@ -42,7 +45,10 @@ export class DatabaseOverviewProvider {
4245
totalKeys = await this.calculateNodesTotalKeys(client);
4346
} else {
4447
nodesInfo = [await this.getNodeInfo(client)];
45-
const [calculatedTotalKeys, calculatedTotalKeysPerDb] = this.calculateTotalKeys(nodesInfo, currentDbIndex);
48+
const [
49+
calculatedTotalKeys,
50+
calculatedTotalKeysPerDb,
51+
] = this.calculateTotalKeys(nodesInfo, currentDbIndex, keyspace);
4652
totalKeys = calculatedTotalKeys;
4753
totalKeysPerDb = calculatedTotalKeysPerDb;
4854
}
@@ -209,9 +215,14 @@ export class DatabaseOverviewProvider {
209215
* In case when shard has multiple logical databases shard total keys = sum of all dbs keys
210216
* @param nodes
211217
* @param index
218+
* @param keyspace
212219
* @private
213220
*/
214-
private calculateTotalKeys(nodes = [], index: number): [number, Record<string, number>] {
221+
private calculateTotalKeys(
222+
nodes = [],
223+
index: number,
224+
keyspace: DatabaseOverviewKeyspace,
225+
): [number, Record<string, number>] {
215226
try {
216227
const masterNodes = DatabaseOverviewProvider.getMasterNodesToWorkWith(nodes);
217228

@@ -238,7 +249,11 @@ export class DatabaseOverviewProvider {
238249

239250
const totalKeys = totalKeysPerDb ? sum(Object.values(totalKeysPerDb)) : undefined;
240251
const dbIndexKeys = totalKeysPerDb[`db${index}`] || 0;
241-
return [totalKeys, dbIndexKeys === totalKeys ? undefined : { [`db${index}`]: dbIndexKeys }];
252+
const calculatedTotalKeysPerDb = keyspace === DatabaseOverviewKeyspace.Full
253+
? totalKeysPerDb
254+
: { [`db${index}`]: dbIndexKeys };
255+
256+
return [totalKeys, dbIndexKeys === totalKeys ? undefined : calculatedTotalKeysPerDb];
242257
} catch (e) {
243258
return [null, null];
244259
}

0 commit comments

Comments
 (0)