diff --git a/src/main/java/org/olat/admin/sysinfo/LargeFilesController.java b/src/main/java/org/olat/admin/sysinfo/LargeFilesController.java index 0d33144fe36576a52dfe3f26add1775fb3617ec1..9ae57138866463935e8689e131dedada0c8ea2fa 100644 --- a/src/main/java/org/olat/admin/sysinfo/LargeFilesController.java +++ b/src/main/java/org/olat/admin/sysinfo/LargeFilesController.java @@ -19,7 +19,6 @@ */ package org.olat.admin.sysinfo; -import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -36,7 +35,6 @@ import org.olat.admin.sysinfo.gui.LargeFilesTrashedCellRenderer; import org.olat.admin.sysinfo.model.LargeFilesTableContentRow; import org.olat.admin.sysinfo.model.LargeFilesTableModel; import org.olat.admin.sysinfo.model.LargeFilesTableModel.LargeFilesTableColumns; -import org.olat.core.commons.persistence.DB; import org.olat.core.commons.persistence.SortKey; import org.olat.core.commons.services.taskexecutor.TaskExecutorManager; import org.olat.core.commons.services.vfs.VFSFilterKeys; @@ -78,7 +76,6 @@ import org.olat.core.util.Formatter; import org.olat.core.util.StringHelper; import org.olat.core.util.mail.ContactList; import org.olat.core.util.mail.ContactMessage; -import org.olat.core.util.vfs.VFSItem; import org.olat.modules.co.ContactFormController; import org.springframework.beans.factory.annotation.Autowired; @@ -119,8 +116,6 @@ public class LargeFilesController extends FormBasicController implements Extende private DialogBoxController confirmMetadataCleanupBox; private CloseableCalloutWindowController pathInfoCalloutCtrl; - @Autowired - private DB dbInstance; @Autowired private VFSRepositoryService vfsRepositoryService; @Autowired @@ -245,6 +240,7 @@ public class LargeFilesController extends FormBasicController implements Extende @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { cleanupMetadataButton = uifactory.addFormLink("metadata.cleanup", formLayout, Link.BUTTON); + cleanupMetadataButton.getComponent().isSuppressDirtyFormWarning(); FormLayoutContainer leftContainer = FormLayoutContainer.createDefaultFormLayout_6_6("filter_left", getTranslator()); leftContainer.setRootForm(mainForm); @@ -534,54 +530,13 @@ public class LargeFilesController extends FormBasicController implements Extende cleanupMetadataButton.setEnabled(false); taskExecutorManager.execute(() -> { - cleanupMetadata(); + vfsRepositoryService.cleanMetadatas(); if(cleanupMetadataButton != null) { cleanupMetadataButton.setIconLeftCSS(""); cleanupMetadataButton.setEnabled(true); } }); } - - private void cleanupMetadata() { - try { - int counter = 0; - int batchSize = 10000; - List<VFSMetadata> metadata; - do { - metadata = vfsRepositoryService.getMetadatas(counter, batchSize); - for(VFSMetadata data:metadata) { - checkMetadata(data); - } - counter += metadata.size(); - getLogger().info("Metadata processed: {}, total metadata processed ({})", metadata.size(), counter); - dbInstance.commitAndCloseSession(); - } while(metadata.size() == batchSize); - } catch (Exception e) { - dbInstance.closeSession(); - logError("", e); - } - } - - private void checkMetadata(VFSMetadata data) { - VFSItem item = vfsRepositoryService.getItemFor(data); - if(item == null || !item.exists()) { - boolean exists = false; - List<VFSRevision> revisions = vfsRepositoryService.getRevisions(data); - for(VFSRevision revision:revisions) { - File revFile = vfsRepositoryService.getRevisionFile(revision); - exists = revFile != null && revFile.exists(); - } - - if(!exists) { - data = vfsRepositoryService.getMetadata(data); - if(data != null) { - getLogger().info("Delete metadata and associated: {}/{}", data.getRelativePath(), data.getFilename()); - vfsRepositoryService.deleteMetadata(data); - dbInstance.commit(); - } - } - } - } @Override public void setEnabled(boolean enable) { diff --git a/src/main/java/org/olat/core/commons/services/vfs/VFSRepositoryService.java b/src/main/java/org/olat/core/commons/services/vfs/VFSRepositoryService.java index 39d49b9c8501d6dffeaec673cf4cab4203ee9074..889c0278cdfc07679bc620c4c925eee6b9d9877a 100644 --- a/src/main/java/org/olat/core/commons/services/vfs/VFSRepositoryService.java +++ b/src/main/java/org/olat/core/commons/services/vfs/VFSRepositoryService.java @@ -71,15 +71,8 @@ public interface VFSRepositoryService { */ public List<VFSMetadata> getChildren(VFSMetadataRef parentMetadata); - /** - * The method is sorted by key, and doesn't fetch any - * associated objects. - * - * @param startPosition Start position (mandatory) - * @param maxResults Max. number of rows to return - * @return A list of metadata without any fetched objects - */ - public List<VFSMetadata> getMetadatas(int startPosition, int maxResults); + + public void cleanMetadatas(); public List<VFSMetadata> getMostDownloaded(VFSMetadata ancestorMetadata, int maxResults); @@ -109,7 +102,7 @@ public interface VFSRepositoryService { * * @param data The metadata to remove */ - public void deleteMetadata(VFSMetadata data); + public int deleteMetadata(VFSMetadata data); /** * Delete the metadata (but not the file), the thumbnails and versions diff --git a/src/main/java/org/olat/core/commons/services/vfs/manager/VFSMetadataDAO.java b/src/main/java/org/olat/core/commons/services/vfs/manager/VFSMetadataDAO.java index 7c47b6feba7d22cf5a93dfe96b4859a4cec83c00..d78899b0d56ce8c13af705c75c42c49048d029f2 100644 --- a/src/main/java/org/olat/core/commons/services/vfs/manager/VFSMetadataDAO.java +++ b/src/main/java/org/olat/core/commons/services/vfs/manager/VFSMetadataDAO.java @@ -160,6 +160,14 @@ public class VFSMetadataDAO { return metadata == null || metadata.isEmpty() ? null : metadata.get(0); } + /** + * The method is sorted by key, and doesn't fetch any + * associated objects. + * + * @param startPosition Start position (mandatory) + * @param maxResults Max. number of rows to return + * @return A list of metadata without any fetched objects + */ public List<VFSMetadata> getMetadatas(int startPosition, int batchSize) { String query = "select metadata from filemetadata metadata order by key"; return dbInstance.getCurrentEntityManager() diff --git a/src/main/java/org/olat/core/commons/services/vfs/manager/VFSRepositoryServiceImpl.java b/src/main/java/org/olat/core/commons/services/vfs/manager/VFSRepositoryServiceImpl.java index 48dc132c9313ea7add790e4f1627731f2df411bd..20706f2a363a476a2d9a99c1d3b4b2600723fd3d 100644 --- a/src/main/java/org/olat/core/commons/services/vfs/manager/VFSRepositoryServiceImpl.java +++ b/src/main/java/org/olat/core/commons/services/vfs/manager/VFSRepositoryServiceImpl.java @@ -193,8 +193,62 @@ public class VFSRepositoryServiceImpl implements VFSRepositoryService, GenericEv } @Override - public List<VFSMetadata> getMetadatas(int startPosition, int maxResults) { - return metadataDao.getMetadatas(startPosition, maxResults); + public void cleanMetadatas() { + try { + int loop = 0; + int counter = 0; + int processed = 0; + int batchSize = 10000; + int maxLoops = 10000;// allow 100'000'000 rows, but prevent an infinite loop in case + int totalDeleted = 0; + List<VFSMetadata> metadata; + do { + metadata = metadataDao.getMetadatas(counter, batchSize); + int deleted = 0; + for(VFSMetadata data:metadata) { + deleted += checkMetadata(data); + } + counter += metadata.size() - deleted; + totalDeleted += deleted; + if(counter < 0) { + counter = 0; + } + loop++; + processed += metadata.size(); + log.info("Metadata processed: {}, deleted {}, total metadata processed ({})", metadata.size(), deleted, processed); + dbInstance.commitAndCloseSession(); + } while(metadata.size() == batchSize && loop < maxLoops); + + log.info("Cleanup metadata ended: deleted {}, total metadata processed ({})", totalDeleted, processed); + } catch (Exception e) { + dbInstance.closeSession(); + log.error("", e); + } + } + + private int checkMetadata(VFSMetadata data) { + int deleted = 0; + + VFSItem item = getItemFor(data); + if(item == null || !item.exists() || item.getName().startsWith("._oo_")) { + boolean exists = false; + List<VFSRevision> revisions = getRevisions(data); + for(VFSRevision revision:revisions) { + File revFile = getRevisionFile(revision); + exists = revFile != null && revFile.exists(); + } + + if(!exists) { + data = getMetadata(data); + if(data != null) { + log.info("Delete metadata and associated: {}/{}", data.getRelativePath(), data.getFilename()); + deleted = deleteMetadata(data); + dbInstance.commit(); + } + } + } + + return deleted; } @Override @@ -376,8 +430,8 @@ public class VFSRepositoryServiceImpl implements VFSRepositoryService, GenericEv } @Override - public void deleteMetadata(VFSMetadata data) { - if(data == null) return; // nothing to do + public int deleteMetadata(VFSMetadata data) { + if(data == null) return 0; // nothing to do List<VFSThumbnailMetadata> thumbnails = thumbnailDao.loadByMetadata(data); for(VFSThumbnailMetadata thumbnail:thumbnails) { @@ -401,11 +455,15 @@ public class VFSRepositoryServiceImpl implements VFSRepositoryService, GenericEv revisionDao.deleteRevision(revision); } + int deleted = 0; + List<VFSMetadata> children = getChildren(data); for(VFSMetadata child:children) { - deleteMetadata(child); + deleted += deleteMetadata(child); } metadataDao.removeMetadata(data); + deleted++; + return deleted; } @Override