This is an automated email from the ASF dual-hosted git repository. rickyma pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-uniffle.git
The following commit(s) were added to refs/heads/master by this push: new bcd6b0788 [#1860] feat(CLI/Coordinator/Dashboard): Add Reg time to AppInfo and Application (#1861) bcd6b0788 is described below commit bcd6b0788a57eb07d4b52796dcdc6e8826d2a14a Author: maobaolong <baoloong...@tencent.com> AuthorDate: Thu Jul 4 15:10:55 2024 +0800 [#1860] feat(CLI/Coordinator/Dashboard): Add Reg time to AppInfo and Application (#1861) ### What changes were proposed in this pull request? Add Reg time to AppInfo and Application ### Why are the changes needed? Fix: #1860 ### Does this PR introduce _any_ user-facing change? `bin/uniffle client-cli -app -host localhost -port 19998` and dashboard app page will display registrationTime of each application. ### How was this patch tested? ```Console bin/uniffle client-cli -app -host localhost -port 19998 host:localhost,port:19998 +--------------------------------------------------------------------------------------------------------------+ | Uniffle Applications | +---------------------------------------+------+---------------------+---------------------+-------------------+ | ApplicationId | User | Registration Time | Last HeartBeatTime | RemoteStoragePath | +---------------------------------------+------+---------------------+---------------------+-------------------+ | app-20240703231912-0003_1720019950472 | user | 2024-07-03 23:19:40 | 2024-07-03 23:21:05 | null | | app-20240703232127-0004_1720020086199 | user | 2024-07-03 23:21:51 | 2024-07-03 23:22:16 | null | +---------------------------------------+------+---------------------+---------------------+-------------------+ ``` <img width="1508" alt="image" src="https://github.com/apache/incubator-uniffle/assets/17329931/96f9703d-6c99-4600-adb5-2ddd8ae48c4d"> --- .../java/org/apache/uniffle/cli/UniffleCLI.java | 4 +- .../org/apache/uniffle/common/Application.java | 21 ++++++++++ .../{web/vo/AppInfoVO.java => AppInfo.java} | 46 ++++++++++++---------- .../uniffle/coordinator/ApplicationManager.java | 43 ++++++++++++-------- .../apache/uniffle/coordinator/QuotaManager.java | 29 ++++++++++---- .../web/resource/ApplicationResource.java | 19 +++++---- .../uniffle/coordinator/web/vo/AppInfoVO.java | 17 ++++++-- .../uniffle/coordinator/QuotaManagerTest.java | 37 +++++++++++------ .../src/main/webapp/src/pages/ApplicationPage.vue | 3 +- 9 files changed, 151 insertions(+), 68 deletions(-) diff --git a/cli/src/main/java/org/apache/uniffle/cli/UniffleCLI.java b/cli/src/main/java/org/apache/uniffle/cli/UniffleCLI.java index 7c7c66fb4..f1ce006c3 100644 --- a/cli/src/main/java/org/apache/uniffle/cli/UniffleCLI.java +++ b/cli/src/main/java/org/apache/uniffle/cli/UniffleCLI.java @@ -59,7 +59,8 @@ public class UniffleCLI extends AbstractCustomCommandLine { private final Option help; private static final List<String> APPLICATIONS_HEADER = - Arrays.asList("ApplicationId", "User", "Last HeartBeatTime", "RemoteStoragePath"); + Arrays.asList( + "ApplicationId", "User", "Registration Time", "Last HeartBeatTime", "RemoteStoragePath"); public UniffleCLI(String shortPrefix, String longPrefix) { allOptions = new Options(); @@ -222,6 +223,7 @@ public class UniffleCLI extends AbstractCustomCommandLine { formattingCLIUtils.addLine( app.getApplicationId(), app.getUser(), + app.getRegistrationTime(), app.getLastHeartBeatTime(), app.getRemoteStoragePath())); } diff --git a/common/src/main/java/org/apache/uniffle/common/Application.java b/common/src/main/java/org/apache/uniffle/common/Application.java index 688144223..27d683e7e 100644 --- a/common/src/main/java/org/apache/uniffle/common/Application.java +++ b/common/src/main/java/org/apache/uniffle/common/Application.java @@ -28,6 +28,7 @@ public class Application implements Comparable<Application> { private String user; private String lastHeartBeatTime; private String remoteStoragePath; + private String registrationTime; public Application() {} @@ -36,12 +37,14 @@ public class Application implements Comparable<Application> { this.user = builder.user; this.lastHeartBeatTime = builder.lastHeartBeatTime; this.remoteStoragePath = builder.remoteStoragePath; + this.registrationTime = builder.registrationTime; } public static class Builder { private String applicationId; private String user; private String lastHeartBeatTime; + private String registrationTime; private String remoteStoragePath; public Builder() {} @@ -61,6 +64,11 @@ public class Application implements Comparable<Application> { return this; } + public Builder registrationTime(long registrationTime) { + this.registrationTime = DateFormatUtils.format(registrationTime, DATE_PATTERN); + return this; + } + public Builder remoteStoragePath(RemoteStorageInfo remoteStorageInfo) { if (remoteStorageInfo != null) { this.remoteStoragePath = remoteStorageInfo.getPath(); @@ -85,6 +93,10 @@ public class Application implements Comparable<Application> { return lastHeartBeatTime; } + public String getRegistrationTime() { + return registrationTime; + } + public String getRemoteStoragePath() { return remoteStoragePath; } @@ -101,6 +113,10 @@ public class Application implements Comparable<Application> { this.lastHeartBeatTime = lastHeartBeatTime; } + public void setRegistrationTime(String registrationTime) { + this.registrationTime = registrationTime; + } + public void setRemoteStoragePath(String remoteStoragePath) { this.remoteStoragePath = remoteStoragePath; } @@ -115,6 +131,7 @@ public class Application implements Comparable<Application> { .append(this.getApplicationId(), otherImpl.getApplicationId()) .append(this.getUser(), otherImpl.getUser()) .append(this.getLastHeartBeatTime(), otherImpl.getLastHeartBeatTime()) + .append(this.getRegistrationTime(), otherImpl.getRegistrationTime()) .append(this.getRemoteStoragePath(), otherImpl.getRemoteStoragePath()) .isEquals(); } @@ -125,6 +142,7 @@ public class Application implements Comparable<Application> { .append(this.getApplicationId()) .append(this.getUser()) .append(this.getLastHeartBeatTime()) + .append(this.getRegistrationTime()) .append(this.getRemoteStoragePath()) .toHashCode(); } @@ -146,6 +164,9 @@ public class Application implements Comparable<Application> { + ", lastHeartBeatTime='" + lastHeartBeatTime + '\'' + + ", registrationTime='" + + registrationTime + + '\'' + ", remoteStoragePath='" + remoteStoragePath + '\'' diff --git a/coordinator/src/main/java/org/apache/uniffle/coordinator/web/vo/AppInfoVO.java b/coordinator/src/main/java/org/apache/uniffle/coordinator/AppInfo.java similarity index 60% copy from coordinator/src/main/java/org/apache/uniffle/coordinator/web/vo/AppInfoVO.java copy to coordinator/src/main/java/org/apache/uniffle/coordinator/AppInfo.java index 87ee82683..d9e9f9953 100644 --- a/coordinator/src/main/java/org/apache/uniffle/coordinator/web/vo/AppInfoVO.java +++ b/coordinator/src/main/java/org/apache/uniffle/coordinator/AppInfo.java @@ -15,27 +15,19 @@ * limitations under the License. */ -package org.apache.uniffle.coordinator.web.vo; +package org.apache.uniffle.coordinator; import java.util.Objects; -public class AppInfoVO implements Comparable<AppInfoVO> { - private String userName; +public class AppInfo implements Comparable<AppInfo> { private String appId; private long updateTime; + private long registrationTime; - public AppInfoVO(String userName, String appId, long updateTime) { - this.userName = userName; + public AppInfo(String appId, long updateTime, long registrationTime) { this.appId = appId; this.updateTime = updateTime; - } - - public String getUserName() { - return userName; - } - - public void setUserName(String userName) { - this.userName = userName; + this.registrationTime = registrationTime; } public String getAppId() { @@ -54,9 +46,17 @@ public class AppInfoVO implements Comparable<AppInfoVO> { this.updateTime = updateTime; } + public long getRegistrationTime() { + return registrationTime; + } + + public void setRegistrationTime(long registrationTime) { + this.registrationTime = registrationTime; + } + @Override - public int compareTo(AppInfoVO appInfoVO) { - return Long.compare(updateTime, appInfoVO.getUpdateTime()); + public int compareTo(AppInfo appInfo) { + return Long.compare(registrationTime, appInfo.getRegistrationTime()); } @Override @@ -64,17 +64,21 @@ public class AppInfoVO implements Comparable<AppInfoVO> { if (this == o) { return true; } - if (!(o instanceof AppInfoVO)) { + if (!(o instanceof AppInfo)) { return false; } - AppInfoVO appInfoVO = (AppInfoVO) o; - return updateTime == appInfoVO.updateTime - && userName.equals(appInfoVO.userName) - && appId.equals(appInfoVO.appId); + AppInfo appInfo = (AppInfo) o; + return updateTime == appInfo.updateTime + && registrationTime == appInfo.registrationTime + && appId.equals(appInfo.appId); } @Override public int hashCode() { - return Objects.hash(userName, appId, updateTime); + return Objects.hash(appId, updateTime, registrationTime); + } + + public static AppInfo createAppInfo(String appId, long updateTime) { + return new AppInfo(appId, updateTime, updateTime); } } diff --git a/coordinator/src/main/java/org/apache/uniffle/coordinator/ApplicationManager.java b/coordinator/src/main/java/org/apache/uniffle/coordinator/ApplicationManager.java index 70e90ffa6..716c22692 100644 --- a/coordinator/src/main/java/org/apache/uniffle/coordinator/ApplicationManager.java +++ b/coordinator/src/main/java/org/apache/uniffle/coordinator/ApplicationManager.java @@ -72,7 +72,7 @@ public class ApplicationManager implements Closeable { private final Map<String, RemoteStorageInfo> availableRemoteStorageInfo; private final ScheduledExecutorService detectStorageScheduler; private final ScheduledExecutorService checkAppScheduler; - private Map<String, Map<String, Long>> currentUserAndApp = JavaUtils.newConcurrentMap(); + private Map<String, Map<String, AppInfo>> currentUserAndApp = JavaUtils.newConcurrentMap(); private Map<String, String> appIdToUser = JavaUtils.newConcurrentMap(); private QuotaManager quotaManager; // it's only for test case to check if status check has problem @@ -130,17 +130,18 @@ public class ApplicationManager implements Closeable { // implementation class // in such case by default, there is no currentUserAndApp, so a unified user implementation // named "user" is used. - Map<String, Long> appAndTime = + Map<String, AppInfo> appAndTime = currentUserAndApp.computeIfAbsent(user, x -> JavaUtils.newConcurrentMap()); appIdToUser.put(appId, user); if (!appAndTime.containsKey(appId)) { CoordinatorMetrics.counterTotalAppNum.inc(); LOG.info("New application is registered: {}", appId); } + AppInfo appInfo = AppInfo.createAppInfo(appId, System.currentTimeMillis()); if (quotaManager != null) { quotaManager.registerApplicationInfo(appId, appAndTime); } else { - appAndTime.put(appId, System.currentTimeMillis()); + appAndTime.put(appId, appInfo); } } @@ -150,8 +151,15 @@ public class ApplicationManager implements Closeable { if (user == null) { registerApplicationInfo(appId, ""); } else { - Map<String, Long> appAndTime = currentUserAndApp.get(user); - appAndTime.put(appId, System.currentTimeMillis()); + Map<String, AppInfo> appAndTime = currentUserAndApp.get(user); + AppInfo appInfo = appAndTime.get(appId); + long currentTimeMs = System.currentTimeMillis(); + if (appInfo != null) { + appInfo.setUpdateTime(currentTimeMs); + } else { + appInfo = new AppInfo(appId, currentTimeMs, currentTimeMs); + appAndTime.put(appId, appInfo); + } } } @@ -317,8 +325,8 @@ public class ApplicationManager implements Closeable { } protected void statusCheck() { - List<Map<String, Long>> appAndNums = Lists.newArrayList(currentUserAndApp.values()); - Map<String, Long> appIds = Maps.newHashMap(); + List<Map<String, AppInfo>> appAndNums = Lists.newArrayList(currentUserAndApp.values()); + Map<String, AppInfo> appIds = Maps.newHashMap(); // The reason for setting an expired uuid here is that there is a scenario where accessCluster // succeeds, // but the registration of shuffle fails, resulting in no normal heartbeat, and no normal update @@ -326,12 +334,12 @@ public class ApplicationManager implements Closeable { // Therefore, an expiration time is set to automatically remove expired uuids Set<String> expiredAppIds = Sets.newHashSet(); try { - for (Map<String, Long> appAndTimes : appAndNums) { - for (Map.Entry<String, Long> appAndTime : appAndTimes.entrySet()) { + for (Map<String, AppInfo> appAndTimes : appAndNums) { + for (Map.Entry<String, AppInfo> appAndTime : appAndTimes.entrySet()) { String appId = appAndTime.getKey(); - long lastReport = appAndTime.getValue(); + AppInfo lastReport = appAndTime.getValue(); appIds.put(appId, lastReport); - if (System.currentTimeMillis() - lastReport > expired) { + if (System.currentTimeMillis() - lastReport.getUpdateTime() > expired) { expiredAppIds.add(appId); appAndTimes.remove(appId); appIdToUser.remove(appId); @@ -416,11 +424,11 @@ public class ApplicationManager implements Closeable { String pHeartBeatEndTime, String appIdRegex) { List<Application> applications = new ArrayList<>(); - for (Map.Entry<String, Map<String, Long>> entry : currentUserAndApp.entrySet()) { + for (Map.Entry<String, Map<String, AppInfo>> entry : currentUserAndApp.entrySet()) { String user = entry.getKey(); - Map<String, Long> apps = entry.getValue(); + Map<String, AppInfo> apps = entry.getValue(); apps.forEach( - (appId, heartBeatTime) -> { + (appId, appInfo) -> { // Filter condition 1: Check whether applicationId is included in the filter list. boolean match = appIds.size() == 0 || appIds.contains(appId); @@ -435,7 +443,7 @@ public class ApplicationManager implements Closeable { || StringUtils.isNotBlank(pHeartBeatEndTime)) { match = matchHeartBeatStartTimeAndEndTime( - pHeartBeatStartTime, pHeartBeatEndTime, heartBeatTime); + pHeartBeatStartTime, pHeartBeatEndTime, appInfo.getUpdateTime()); } // If it meets expectations, add to the list to be returned. @@ -446,7 +454,8 @@ public class ApplicationManager implements Closeable { new Application.Builder() .applicationId(appId) .user(user) - .lastHeartBeatTime(heartBeatTime) + .lastHeartBeatTime(appInfo.getUpdateTime()) + .registrationTime(appInfo.getRegistrationTime()) .remoteStoragePath(remoteStorageInfo) .build(); applications.add(application); @@ -527,7 +536,7 @@ public class ApplicationManager implements Closeable { return REMOTE_PATH_SCHEMA; } - public Map<String, Map<String, Long>> getCurrentUserAndApp() { + public Map<String, Map<String, AppInfo>> getCurrentUserAndApp() { return currentUserAndApp; } diff --git a/coordinator/src/main/java/org/apache/uniffle/coordinator/QuotaManager.java b/coordinator/src/main/java/org/apache/uniffle/coordinator/QuotaManager.java index d661f90df..72c462933 100644 --- a/coordinator/src/main/java/org/apache/uniffle/coordinator/QuotaManager.java +++ b/coordinator/src/main/java/org/apache/uniffle/coordinator/QuotaManager.java @@ -44,7 +44,7 @@ import org.apache.uniffle.coordinator.metric.CoordinatorMetrics; /** QuotaManager is a manager for resource restriction. */ public class QuotaManager { private static final Logger LOG = LoggerFactory.getLogger(QuotaManager.class); - private final Map<String, Map<String, Long>> currentUserAndApp = JavaUtils.newConcurrentMap(); + private final Map<String, Map<String, AppInfo>> currentUserAndApp = JavaUtils.newConcurrentMap(); private final Map<String, String> appIdToUser = JavaUtils.newConcurrentMap(); private final String quotaFilePath; private final Integer quotaAppNum; @@ -116,7 +116,7 @@ public class QuotaManager { } public boolean checkQuota(String user, String uuid) { - Map<String, Long> appAndTimes = + Map<String, AppInfo> appAndTimes = currentUserAndApp.computeIfAbsent(user, x -> JavaUtils.newConcurrentMap()); Integer userAppQuotaNum = defaultUserApps.computeIfAbsent(user, x -> quotaAppNum); synchronized (this) { @@ -124,26 +124,41 @@ public class QuotaManager { if (userAppQuotaNum >= 0 && currentAppNum >= userAppQuotaNum) { return true; } else { - appAndTimes.put(uuid, System.currentTimeMillis()); + // thread safe is guaranteed by synchronized + AppInfo appInfo = appAndTimes.get(uuid); + long currentTimeMillis = System.currentTimeMillis(); + if (appInfo == null) { + appInfo = new AppInfo(uuid, currentTimeMillis, currentTimeMillis); + appAndTimes.put(uuid, appInfo); + } else { + appInfo.setUpdateTime(currentTimeMillis); + } CoordinatorMetrics.gaugeRunningAppNumToUser.labels(user).inc(); return false; } } } - public void registerApplicationInfo(String appId, Map<String, Long> appAndTime) { + public void registerApplicationInfo(String appId, Map<String, AppInfo> appAndTime) { long currentTimeMillis = System.currentTimeMillis(); String[] appIdAndUuid = appId.split("_"); String uuidFromApp = appIdAndUuid[appIdAndUuid.length - 1]; // if appId created successfully, we need to remove the uuid synchronized (this) { appAndTime.remove(uuidFromApp); - appAndTime.put(appId, currentTimeMillis); + // thread safe is guaranteed by synchronized + AppInfo appInfo = appAndTime.get(appId); + if (appInfo == null) { + appInfo = new AppInfo(appId, currentTimeMillis, currentTimeMillis); + appAndTime.put(appId, appInfo); + } else { + appInfo.setUpdateTime(currentTimeMillis); + } } } protected void updateQuotaMetrics() { - for (Map.Entry<String, Map<String, Long>> userAndApp : currentUserAndApp.entrySet()) { + for (Map.Entry<String, Map<String, AppInfo>> userAndApp : currentUserAndApp.entrySet()) { String user = userAndApp.getKey(); try { CoordinatorMetrics.gaugeRunningAppNumToUser.labels(user).set(userAndApp.getValue().size()); @@ -158,7 +173,7 @@ public class QuotaManager { return defaultUserApps; } - public Map<String, Map<String, Long>> getCurrentUserAndApp() { + public Map<String, Map<String, AppInfo>> getCurrentUserAndApp() { return currentUserAndApp; } diff --git a/coordinator/src/main/java/org/apache/uniffle/coordinator/web/resource/ApplicationResource.java b/coordinator/src/main/java/org/apache/uniffle/coordinator/web/resource/ApplicationResource.java index 7106d66d1..12558639a 100644 --- a/coordinator/src/main/java/org/apache/uniffle/coordinator/web/resource/ApplicationResource.java +++ b/coordinator/src/main/java/org/apache/uniffle/coordinator/web/resource/ApplicationResource.java @@ -32,6 +32,7 @@ import org.apache.hbase.thirdparty.javax.ws.rs.core.MediaType; import org.apache.uniffle.common.web.resource.BaseResource; import org.apache.uniffle.common.web.resource.Response; +import org.apache.uniffle.coordinator.AppInfo; import org.apache.uniffle.coordinator.ApplicationManager; import org.apache.uniffle.coordinator.web.vo.AppInfoVO; import org.apache.uniffle.coordinator.web.vo.UserAppNumVO; @@ -57,10 +58,11 @@ public class ApplicationResource extends BaseResource { public Response<List<UserAppNumVO>> getUserApps() { return execute( () -> { - Map<String, Map<String, Long>> currentUserAndApp = + Map<String, Map<String, AppInfo>> currentUserAndApp = getApplicationManager().getCurrentUserAndApp(); List<UserAppNumVO> usercnt = new ArrayList<>(); - for (Map.Entry<String, Map<String, Long>> stringMapEntry : currentUserAndApp.entrySet()) { + for (Map.Entry<String, Map<String, AppInfo>> stringMapEntry : + currentUserAndApp.entrySet()) { String userName = stringMapEntry.getKey(); usercnt.add(new UserAppNumVO(userName, stringMapEntry.getValue().size())); } @@ -76,16 +78,19 @@ public class ApplicationResource extends BaseResource { return execute( () -> { List<AppInfoVO> userToAppList = new ArrayList<>(); - Map<String, Map<String, Long>> currentUserAndApp = + Map<String, Map<String, AppInfo>> currentUserAndApp = getApplicationManager().getCurrentUserAndApp(); - for (Map.Entry<String, Map<String, Long>> userAppIdTimestampMap : + for (Map.Entry<String, Map<String, AppInfo>> userAppIdTimestampMap : currentUserAndApp.entrySet()) { - String userName = userAppIdTimestampMap.getKey(); - for (Map.Entry<String, Long> appIdTimestampMap : + for (Map.Entry<String, AppInfo> appIdTimestampMap : userAppIdTimestampMap.getValue().entrySet()) { + AppInfo appInfo = appIdTimestampMap.getValue(); userToAppList.add( new AppInfoVO( - userName, appIdTimestampMap.getKey(), appIdTimestampMap.getValue())); + userAppIdTimestampMap.getKey(), + appInfo.getAppId(), + appInfo.getUpdateTime(), + appInfo.getRegistrationTime())); } } // Display is inverted by the submission time of the application. diff --git a/coordinator/src/main/java/org/apache/uniffle/coordinator/web/vo/AppInfoVO.java b/coordinator/src/main/java/org/apache/uniffle/coordinator/web/vo/AppInfoVO.java index 87ee82683..3d80f0e01 100644 --- a/coordinator/src/main/java/org/apache/uniffle/coordinator/web/vo/AppInfoVO.java +++ b/coordinator/src/main/java/org/apache/uniffle/coordinator/web/vo/AppInfoVO.java @@ -23,11 +23,13 @@ public class AppInfoVO implements Comparable<AppInfoVO> { private String userName; private String appId; private long updateTime; + private long registrationTime; - public AppInfoVO(String userName, String appId, long updateTime) { + public AppInfoVO(String userName, String appId, long updateTime, long registrationTime) { this.userName = userName; this.appId = appId; this.updateTime = updateTime; + this.registrationTime = registrationTime; } public String getUserName() { @@ -54,9 +56,17 @@ public class AppInfoVO implements Comparable<AppInfoVO> { this.updateTime = updateTime; } + public long getRegistrationTime() { + return registrationTime; + } + + public void setRegistrationTime(long registrationTime) { + this.registrationTime = registrationTime; + } + @Override public int compareTo(AppInfoVO appInfoVO) { - return Long.compare(updateTime, appInfoVO.getUpdateTime()); + return Long.compare(registrationTime, appInfoVO.getRegistrationTime()); } @Override @@ -69,12 +79,13 @@ public class AppInfoVO implements Comparable<AppInfoVO> { } AppInfoVO appInfoVO = (AppInfoVO) o; return updateTime == appInfoVO.updateTime + && registrationTime == appInfoVO.registrationTime && userName.equals(appInfoVO.userName) && appId.equals(appInfoVO.appId); } @Override public int hashCode() { - return Objects.hash(userName, appId, updateTime); + return Objects.hash(userName, appId, updateTime, registrationTime); } } diff --git a/coordinator/src/test/java/org/apache/uniffle/coordinator/QuotaManagerTest.java b/coordinator/src/test/java/org/apache/uniffle/coordinator/QuotaManagerTest.java index 41be903c2..54c0f9b47 100644 --- a/coordinator/src/test/java/org/apache/uniffle/coordinator/QuotaManagerTest.java +++ b/coordinator/src/test/java/org/apache/uniffle/coordinator/QuotaManagerTest.java @@ -97,14 +97,20 @@ public class QuotaManagerTest { conf.setInteger(CoordinatorConf.COORDINATOR_QUOTA_DEFAULT_APP_NUM, 5); try (ApplicationManager applicationManager = new ApplicationManager(conf)) { final AtomicInteger uuid = new AtomicInteger(); - Map<String, Long> uuidAndTime = JavaUtils.newConcurrentMap(); - uuidAndTime.put(String.valueOf(uuid.incrementAndGet()), System.currentTimeMillis()); - uuidAndTime.put(String.valueOf(uuid.incrementAndGet()), System.currentTimeMillis()); - uuidAndTime.put(String.valueOf(uuid.incrementAndGet()), System.currentTimeMillis()); - uuidAndTime.put(String.valueOf(uuid.incrementAndGet()), System.currentTimeMillis()); + Map<String, AppInfo> uuidAndTime = JavaUtils.newConcurrentMap(); + String appId = String.valueOf(uuid.incrementAndGet()); + uuidAndTime.put(appId, AppInfo.createAppInfo(appId, System.currentTimeMillis())); + appId = String.valueOf(uuid.incrementAndGet()); + uuidAndTime.put(appId, AppInfo.createAppInfo(appId, System.currentTimeMillis())); + appId = String.valueOf(uuid.incrementAndGet()); + uuidAndTime.put(appId, AppInfo.createAppInfo(appId, System.currentTimeMillis())); + appId = String.valueOf(uuid.incrementAndGet()); + uuidAndTime.put(appId, AppInfo.createAppInfo(appId, System.currentTimeMillis())); final int i1 = uuid.incrementAndGet(); - uuidAndTime.put(String.valueOf(i1), System.currentTimeMillis()); - Map<String, Long> appAndTime = + uuidAndTime.put( + String.valueOf(i1), + AppInfo.createAppInfo(String.valueOf(i1), System.currentTimeMillis())); + Map<String, AppInfo> appAndTime = applicationManager .getQuotaManager() .getCurrentUserAndApp() @@ -184,7 +190,7 @@ public class QuotaManagerTest { .until(() -> applicationManager.getDefaultUserApps().size() > 2); QuotaManager quotaManager = applicationManager.getQuotaManager(); - Map<String, Map<String, Long>> currentUserAndApp = quotaManager.getCurrentUserAndApp(); + Map<String, Map<String, AppInfo>> currentUserAndApp = quotaManager.getCurrentUserAndApp(); currentUserAndApp.computeIfAbsent("user1", x -> mockUUidAppAndTime(30)); currentUserAndApp.computeIfAbsent("user2", x -> mockUUidAppAndTime(20)); @@ -211,11 +217,20 @@ public class QuotaManagerTest { return String.valueOf(uuid.incrementAndGet()); } - private Map<String, Long> mockUUidAppAndTime(int mockAppNum) { - Map<String, Long> uuidAndTime = JavaUtils.newConcurrentMap(); + private Map<String, AppInfo> mockUUidAppAndTime(int mockAppNum) { + Map<String, AppInfo> uuidAndTime = JavaUtils.newConcurrentMap(); for (int i = 0; i < mockAppNum; i++) { - uuidAndTime.put(mockUUidAppId(), System.currentTimeMillis()); + String appId = mockUUidAppId(); + long currentTimeMs = System.currentTimeMillis(); + AppInfo appInfo = uuidAndTime.get(appId); + if (appInfo != null) { + appInfo.setUpdateTime(currentTimeMs); + } else { + appInfo = new AppInfo(appId, currentTimeMs, currentTimeMs); + uuidAndTime.put(appId, appInfo); + } } + return uuidAndTime; } } diff --git a/dashboard/src/main/webapp/src/pages/ApplicationPage.vue b/dashboard/src/main/webapp/src/pages/ApplicationPage.vue index 33d1e546c..e3ef4cab9 100644 --- a/dashboard/src/main/webapp/src/pages/ApplicationPage.vue +++ b/dashboard/src/main/webapp/src/pages/ApplicationPage.vue @@ -43,6 +43,7 @@ <el-table :data="pageData.appInfoData" height="250" style="width: 100%"> <el-table-column prop="appId" label="AppId" min-width="180" /> <el-table-column prop="userName" label="UserName" min-width="180" /> + <el-table-column prop="registrationTime" label="Registration Time" min-width="180" :formatter="dateFormatter" /> <el-table-column prop="updateTime" label="Update Time" min-width="180" :formatter="dateFormatter" /> </el-table> </div> @@ -60,7 +61,7 @@ export default { const pageData = reactive({ apptotal: {}, userAppCount: [{}], - appInfoData: [{ appId: '', userName: '', updateTime: '' }] + appInfoData: [{ appId: '', userName: '', registrationTime: '', updateTime: '' }] }) const currentServerStore = useCurrentServerStore()