Skip to content

Commit 4bff890

Browse files
committed
Merge pull request #548 from UnifiedViews/feature/pipelineAndExecutionViewsPerformance
Pipeline, execution and schedule views performance issues fix to 2.2.x develop
2 parents 4c0d1f7 + dbd6fe2 commit 4bff890

3 files changed

Lines changed: 206 additions & 75 deletions

File tree

frontend/src/main/java/cz/cuni/mff/xrg/odcs/frontend/gui/views/Scheduler.java

Lines changed: 107 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import java.text.DateFormat;
2020
import java.util.Date;
21+
import java.util.HashMap;
2122
import java.util.Iterator;
2223
import java.util.List;
2324
import java.util.Map;
@@ -32,8 +33,6 @@
3233
import org.tepi.filtertable.paged.PagedTableChangeEvent;
3334
import org.vaadin.dialogs.ConfirmDialog;
3435

35-
import ru.xpoft.vaadin.VaadinView;
36-
3736
import com.github.wolfie.refresher.Refresher;
3837
import com.vaadin.data.Property;
3938
import com.vaadin.data.util.IndexedContainer;
@@ -42,9 +41,15 @@
4241
import com.vaadin.server.Page;
4342
import com.vaadin.server.Resource;
4443
import com.vaadin.server.ThemeResource;
45-
import com.vaadin.ui.*;
44+
import com.vaadin.ui.Button;
4645
import com.vaadin.ui.Button.ClickEvent;
4746
import com.vaadin.ui.Button.ClickListener;
47+
import com.vaadin.ui.CustomTable;
48+
import com.vaadin.ui.Embedded;
49+
import com.vaadin.ui.HorizontalLayout;
50+
import com.vaadin.ui.Notification;
51+
import com.vaadin.ui.UI;
52+
import com.vaadin.ui.VerticalLayout;
4853
import com.vaadin.ui.Window.CloseEvent;
4954
import com.vaadin.ui.Window.CloseListener;
5055

@@ -68,6 +73,7 @@
6873
import cz.cuni.mff.xrg.odcs.frontend.i18n.Messages;
6974
import cz.cuni.mff.xrg.odcs.frontend.navigation.Address;
7075
import cz.cuni.mff.xrg.odcs.frontend.navigation.ParametersHandler;
76+
import ru.xpoft.vaadin.VaadinView;
7177

7278
/**
7379
* GUI for Scheduler page which opens from the main menu. Contains table with
@@ -147,6 +153,17 @@ public class Scheduler extends ViewComponent implements PostLogoutCleaner, Prese
147153

148154
private boolean isMainLayoutInitialized = false;
149155

156+
/**
157+
* Pipeline cache for light pipelines loading
158+
*/
159+
private Map<Long, Schedule> scheduleCache = new HashMap<>();
160+
161+
private static final int CACHE_MAX_SIZE = 100;
162+
163+
private static final int CACHE_TIMEOUT = 300000;
164+
165+
private Date lightCacheLastReload = new Date();
166+
150167
/**
151168
* The constructor should first build the main layout, set the composition
152169
* root and then do any custom initialization.
@@ -170,25 +187,45 @@ public void enter(ViewChangeEvent event) {
170187
}
171188
setCompositionRoot(mainLayout);
172189

173-
refreshManager = ((AppEntry) UI.getCurrent()).getRefreshManager();
174-
refreshManager.addListener(RefreshManager.SCHEDULER, new Refresher.RefreshListener() {
190+
addRefreshListener();
191+
192+
setParameters(ParametersHandler.getConfiguration(event.getParameters()));
193+
}
194+
195+
@Override
196+
public Object enter() {
197+
if (!isMainLayoutInitialized) {
198+
buildMainLayout();
199+
isMainLayoutInitialized = true;
200+
}
201+
setCompositionRoot(mainLayout);
202+
203+
addRefreshListener();
204+
205+
return this;
206+
}
207+
208+
private void addRefreshListener() {
209+
this.refreshManager = ((AppEntry) UI.getCurrent()).getRefreshManager();
210+
this.refreshManager.addListener(RefreshManager.SCHEDULER, new Refresher.RefreshListener() {
175211
private long lastRefreshFinished = 0;
176212

177213
@Override
178214
public void refresh(Refresher source) {
179215
if (new Date().getTime() - lastRefreshFinished > RefreshManager.MIN_REFRESH_INTERVAL) {
180216
boolean hasModifiedExecutions = pipelineFacade.hasModifiedExecutions(lastLoad);
181217
if (hasModifiedExecutions) {
218+
LOG.debug("Modified executions found, refreshing ...");
182219
lastLoad = new Date();
183220
refreshData();
221+
LOG.debug("Scheduler refreshed.");
184222
}
185-
LOG.debug("Scheduler refreshed.");
223+
186224
lastRefreshFinished = new Date().getTime();
187225
}
188226
}
189227
});
190-
refreshManager.triggerRefresh();
191-
setParameters(ParametersHandler.getConfiguration(event.getParameters()));
228+
this.refreshManager.triggerRefresh();
192229
}
193230

194231
/**
@@ -460,15 +497,17 @@ private static String getScheduledByDisplayName(Schedule schedule) {
460497
/**
461498
* Calls for refresh table {@link #schedulerTable}.
462499
*/
500+
@SuppressWarnings("deprecation")
463501
private void refreshData() {
502+
List<Schedule> schedules = this.scheduleFacade.getAllSchedules();
503+
reloadScheduleCache(schedules);
464504
int page = schedulerTable.getCurrentPage();
465-
tableData = getTableData(scheduleFacade.getAllSchedules());
505+
tableData = getTableData(schedules);
466506
schedulerTable.setContainerDataSource(tableData);
467507
schedulerTable.setCurrentPage(page);
468508
schedulerTable.setVisibleColumns((Object[]) visibleCols);
469509
schedulerTable.setFilterFieldVisible("commands", false);
470510
schedulerTable.setFilterFieldVisible("duration", false);
471-
472511
}
473512

474513
/**
@@ -486,13 +525,14 @@ private void showSchedulePipeline(Long id, Long pipelineId) {
486525
@Override
487526
public void windowClose(CloseEvent e) {
488527
refreshData();
528+
addRefreshListener();
489529
}
490530
});
491531
}
492532

493533
Schedule schedule = null;
494534
if (id != null) {
495-
schedule = scheduleFacade.getSchedule(id);
535+
schedule = getSchedule(id);
496536
}
497537
schedulePipeline.setSelectedSchedule(schedule);
498538
schedulePipeline.enableComboPipeline();
@@ -520,7 +560,7 @@ class actionColumnGenerator implements CustomTable.ColumnGenerator {
520560
@Override
521561
public Object generateCell(final CustomTable source, final Object itemId, Object columnId) {
522562
final Long schId = Long.parseLong(tableData.getContainerProperty(itemId, "schid").getValue().toString());
523-
Schedule schedule = scheduleFacade.getSchedule(schId);
563+
Schedule schedule = getSchedule(schId);
524564
Property propStatus = source.getItem(itemId).getItemProperty("status");
525565

526566
HorizontalLayout layout = new HorizontalLayout();
@@ -589,22 +629,22 @@ public void buttonClick(ClickEvent event) {
589629
deleteButton.addClickListener(new ClickListener() {
590630
@Override
591631
public void buttonClick(ClickEvent event) {
592-
scheduleDel = scheduleFacade.getSchedule(schId);
632+
scheduleDel = getSchedule(schId);
593633

594634
//open confirmation dialog
595635
ConfirmDialog.show(UI.getCurrent(), Messages.getString("Scheduler.delete.scheduling"),
596636
Messages.getString("Scheduler.delete.scheduling.description", scheduleDel.getPipeline().getName().toString()), Messages.getString("Scheduler.delete.scheduling.deleteButton"), Messages.getString("Scheduler.delete.scheduling.calcelButton"),
597637
new ConfirmDialog.Listener() {
598-
private static final long serialVersionUID = 1L;
599-
600-
@Override
601-
public void onClose(ConfirmDialog cd) {
602-
if (cd.isConfirmed()) {
603-
scheduleFacade.delete(scheduleDel);
604-
refreshData();
605-
}
606-
}
607-
});
638+
private static final long serialVersionUID = 1L;
639+
640+
@Override
641+
public void onClose(ConfirmDialog cd) {
642+
if (cd.isConfirmed()) {
643+
scheduleFacade.delete(scheduleDel);
644+
refreshData();
645+
}
646+
}
647+
});
608648
}
609649
});
610650
if (canDelete(schedule)) {
@@ -616,9 +656,9 @@ public void onClose(ConfirmDialog cd) {
616656
}
617657

618658
private void setScheduleEnabled(Long schId, boolean enabled) {
619-
Schedule schedule = scheduleFacade.getSchedule(schId);
659+
Schedule schedule = getSchedule(schId);
620660
schedule.setEnabled(enabled);
621-
scheduleFacade.save(schedule);
661+
this.scheduleFacade.save(schedule);
622662
}
623663

624664
boolean canDelete(Schedule schedule) {
@@ -663,36 +703,6 @@ private void changeURI(Long scheduleId) {
663703
((AppEntry) UI.getCurrent()).setUriFragment(handler.getUriFragment(), false);
664704
}
665705

666-
@Override
667-
public Object enter() {
668-
if (!isMainLayoutInitialized) {
669-
buildMainLayout();
670-
isMainLayoutInitialized = true;
671-
}
672-
setCompositionRoot(mainLayout);
673-
674-
refreshManager = ((AppEntry) UI.getCurrent()).getRefreshManager();
675-
refreshManager.addListener(RefreshManager.SCHEDULER, new Refresher.RefreshListener() {
676-
private long lastRefreshFinished = 0;
677-
678-
@Override
679-
public void refresh(Refresher source) {
680-
if (new Date().getTime() - lastRefreshFinished > RefreshManager.MIN_REFRESH_INTERVAL) {
681-
boolean hasModifiedExecutions = pipelineFacade.hasModifiedExecutions(lastLoad);
682-
if (hasModifiedExecutions) {
683-
lastLoad = new Date();
684-
refreshData();
685-
}
686-
LOG.debug("Scheduler refreshed.");
687-
lastRefreshFinished = new Date().getTime();
688-
}
689-
}
690-
});
691-
refreshManager.triggerRefresh();
692-
693-
return this;
694-
}
695-
696706
@Override
697707
public void setParameters(Object configuration) {
698708
if (configuration != null && Map.class.isAssignableFrom(configuration.getClass())) {
@@ -767,7 +777,7 @@ public void showDebugEventHandler(long scheduleId) {
767777
if (!schedulerTable.getItemIds().contains((new Long(scheduleId)).intValue())) {
768778
return;
769779
}
770-
Schedule schedule = scheduleFacade.getSchedule(scheduleId);
780+
Schedule schedule = getSchedule(scheduleId);
771781
if (schedule == null) {
772782
Notification.show(Messages.getString("Scheduler.0", scheduleId), Notification.Type.ERROR_MESSAGE);
773783
return;
@@ -782,4 +792,45 @@ public void pageChangedHandler(Integer newPageNumber) {
782792
((AppEntry) UI.getCurrent()).setUriFragment(handler.getUriFragment(), false);
783793
}
784794

795+
/**
796+
* Get cached schedule or retrieve from database
797+
*
798+
* @param scheduleId
799+
* @return copy of schedule
800+
*/
801+
private Schedule getSchedule(long scheduleId) {
802+
if (this.scheduleCache.size() >= CACHE_MAX_SIZE) {
803+
LOG.debug("Light pipeline cache size exceeded, reloading ...");
804+
reloadScheduleCache();
805+
}
806+
807+
if (this.lightCacheLastReload.before(new Date(new Date().getTime() - CACHE_TIMEOUT))) {
808+
LOG.debug("Light pipeline cache timeout, reloading ...");
809+
reloadScheduleCache();
810+
}
811+
812+
Schedule schedule = null;
813+
if (this.scheduleCache.containsKey(scheduleId)) {
814+
schedule = this.scheduleCache.get(scheduleId);
815+
} else {
816+
schedule = this.scheduleFacade.getSchedule(scheduleId);
817+
this.scheduleCache.put(scheduleId, schedule);
818+
}
819+
820+
return schedule;
821+
}
822+
823+
private void reloadScheduleCache() {
824+
this.scheduleCache.clear();
825+
this.lightCacheLastReload = new Date();
826+
}
827+
828+
private void reloadScheduleCache(List<Schedule> schedules) {
829+
this.scheduleCache.clear();
830+
for (Schedule schedule : schedules) {
831+
scheduleCache.put(schedule.getId(), schedule);
832+
}
833+
this.lightCacheLastReload = new Date();
834+
}
835+
785836
}

0 commit comments

Comments
 (0)