From c0f36060912afe5dde3e7abd7e1d811df491914a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20Thomas?= Date: Fri, 8 Mar 2019 22:08:51 +0100 Subject: [PATCH 1/9] Force database checkpoints on 'Clean-up' and 'Scan' actions This will only affect the (embedded/legacy) HSQLDB driver. Even though cff97ea9 should prevent the db log from getting uncontrollably large, the 'Clean-up database' and 'Scan' actions will additionally force a checkpoint to ensure this happens on big operations. --- .../MusicFolderSettingsController.java | 1 + .../org/airsonic/player/dao/AbstractDao.java | 2 + .../org/airsonic/player/dao/DaoHelper.java | 10 +++++ .../airsonic/player/dao/GenericDaoHelper.java | 39 +++++++++++++++++++ .../player/service/MediaScannerService.java | 1 + 5 files changed, 53 insertions(+) diff --git a/airsonic-main/src/main/java/org/airsonic/player/controller/MusicFolderSettingsController.java b/airsonic-main/src/main/java/org/airsonic/player/controller/MusicFolderSettingsController.java index 13f948b7..b5a657d9 100644 --- a/airsonic-main/src/main/java/org/airsonic/player/controller/MusicFolderSettingsController.java +++ b/airsonic-main/src/main/java/org/airsonic/player/controller/MusicFolderSettingsController.java @@ -96,6 +96,7 @@ public class MusicFolderSettingsController { artistDao.expunge(); albumDao.expunge(); mediaFileDao.expunge(); + mediaFileDao.checkpoint(); } private List wrap(List musicFolders) { diff --git a/airsonic-main/src/main/java/org/airsonic/player/dao/AbstractDao.java b/airsonic-main/src/main/java/org/airsonic/player/dao/AbstractDao.java index 107bff9b..a01836ab 100644 --- a/airsonic-main/src/main/java/org/airsonic/player/dao/AbstractDao.java +++ b/airsonic-main/src/main/java/org/airsonic/player/dao/AbstractDao.java @@ -189,4 +189,6 @@ public class AbstractDao { this.daoHelper = daoHelper; } + public boolean checkpoint() { return daoHelper.checkpoint(); } + } diff --git a/airsonic-main/src/main/java/org/airsonic/player/dao/DaoHelper.java b/airsonic-main/src/main/java/org/airsonic/player/dao/DaoHelper.java index a0e5b4b8..5a5c2a84 100644 --- a/airsonic-main/src/main/java/org/airsonic/player/dao/DaoHelper.java +++ b/airsonic-main/src/main/java/org/airsonic/player/dao/DaoHelper.java @@ -46,4 +46,14 @@ public interface DaoHelper { NamedParameterJdbcTemplate getNamedParameterJdbcTemplate(); DataSource getDataSource(); + + /** + * Tries to perform a checkpoint against the database, if supported + * + * Database checkpoints will make sure that the database is written on the disk + * and optimize on-disk storage. + * + * @return true if the checkpoint succeeded + */ + public boolean checkpoint(); } diff --git a/airsonic-main/src/main/java/org/airsonic/player/dao/GenericDaoHelper.java b/airsonic-main/src/main/java/org/airsonic/player/dao/GenericDaoHelper.java index 792df5e0..513ee03f 100644 --- a/airsonic-main/src/main/java/org/airsonic/player/dao/GenericDaoHelper.java +++ b/airsonic-main/src/main/java/org/airsonic/player/dao/GenericDaoHelper.java @@ -1,12 +1,20 @@ package org.airsonic.player.dao; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; +import org.springframework.jdbc.datasource.DataSourceUtils; import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.DatabaseMetaData; + public class GenericDaoHelper implements DaoHelper { + private static final Logger LOG = LoggerFactory.getLogger(GenericDaoHelper.class); + final JdbcTemplate jdbcTemplate; final NamedParameterJdbcTemplate namedParameterJdbcTemplate; @@ -35,4 +43,35 @@ public class GenericDaoHelper implements DaoHelper { public DataSource getDataSource() { return dataSource; } + + @Override + public boolean checkpoint() { + + try { + Connection conn = DataSourceUtils.getConnection(getJdbcTemplate().getDataSource()); + DatabaseMetaData meta = conn.getMetaData(); + String productName = meta.getDatabaseProductName(); + int productVersion = meta.getDatabaseMajorVersion(); + + // HSQLDB (at least version 1) does not handle automatic checkpoints very well by default. + // This makes sure the temporary log is actually written to more persistent storage. + if (productName.equals("HSQL Database Engine") && (productVersion == 1 || productVersion == 2)) { + LOG.info("Performing database checkpoint"); + getJdbcTemplate().execute("CHECKPOINT DEFRAG"); + return true; + } else { + LOG.debug("Database checkpoint not implemented for '" + productName + "'"); + return false; + } + } + + // Since this method is a best-effort operation, we don't want to show + // a message if the checkpoint failed ; just assume the operation is + // unsupported. + catch(java.sql.SQLException e) { + LOG.debug("An exception occurred during database checkpoint: " + e.toString()); + } + + return false; + } } diff --git a/airsonic-main/src/main/java/org/airsonic/player/service/MediaScannerService.java b/airsonic-main/src/main/java/org/airsonic/player/service/MediaScannerService.java index 427346b5..b4f6ee96 100644 --- a/airsonic-main/src/main/java/org/airsonic/player/service/MediaScannerService.java +++ b/airsonic-main/src/main/java/org/airsonic/player/service/MediaScannerService.java @@ -156,6 +156,7 @@ public class MediaScannerService { public void run() { doScanLibrary(); playlistService.importPlaylists(); + mediaFileDao.checkpoint(); } }; From c79c02d4493d441a9bcc24d95e00ea30ceb9879a Mon Sep 17 00:00:00 2001 From: Iwao AVE! Date: Thu, 2 May 2019 20:30:48 +0900 Subject: [PATCH 2/9] Updated CHECKPOINT / DEFRAG syntax for HSQLDB 2. Signed-off-by: Iwao AVE! --- .../liquibase/10.2/setup-hsqldb-checkpoint-defrag.xml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/airsonic-main/src/main/resources/liquibase/10.2/setup-hsqldb-checkpoint-defrag.xml b/airsonic-main/src/main/resources/liquibase/10.2/setup-hsqldb-checkpoint-defrag.xml index 7f42743b..a028b8ce 100644 --- a/airsonic-main/src/main/resources/liquibase/10.2/setup-hsqldb-checkpoint-defrag.xml +++ b/airsonic-main/src/main/resources/liquibase/10.2/setup-hsqldb-checkpoint-defrag.xml @@ -4,6 +4,8 @@ xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd"> + 7:890e52428bbc2a792fea1e026a4b7610 + @@ -13,12 +15,12 @@ Defragment the database before enabling auto defrag, so that the biggest part of the work is done during migration. - SET LOGSIZE 64; - Automatically run a CHECKPOINT when the log is above 64MB. + SET FILES LOG SIZE 64; + Automatically run a CHECKPOINT when the log is above 64MB. http://hsqldb.org/doc/guide/management-chapt.html#N150AB - SET CHECKPOINT DEFRAG 32; - Automatically defragment on CHECKPOINT when the wasted space is above 32MB. + SET FILES DEFRAG 50; + Sets the threshold in percentage for performing a DEFRAG during a checkpoint. http://hsqldb.org/doc/guide/management-chapt.html#N1506D From 54e444b03c9a1c05e958a2667c1bf3df921c9634 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20Thomas?= Date: Fri, 8 Mar 2019 22:22:25 +0100 Subject: [PATCH 3/9] Make CHECKPOINT / DEFRAG syntax work for both HSQLDB 1 & 2 --- .../10.2/setup-hsqldb-checkpoint-defrag.xml | 36 ++++++++++++++++--- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/airsonic-main/src/main/resources/liquibase/10.2/setup-hsqldb-checkpoint-defrag.xml b/airsonic-main/src/main/resources/liquibase/10.2/setup-hsqldb-checkpoint-defrag.xml index a028b8ce..8377af76 100644 --- a/airsonic-main/src/main/resources/liquibase/10.2/setup-hsqldb-checkpoint-defrag.xml +++ b/airsonic-main/src/main/resources/liquibase/10.2/setup-hsqldb-checkpoint-defrag.xml @@ -2,12 +2,13 @@ xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd"> - - - 7:890e52428bbc2a792fea1e026a4b7610 + - + + + + @@ -26,4 +27,31 @@ + + + 7:890e52428bbc2a792fea1e026a4b7610 + + + + + + + + + + CHECKPOINT DEFRAG; + Defragment the database before enabling auto defrag, so that the biggest part of the work is done during migration. + + + SET LOGSIZE 64; + Automatically run a CHECKPOINT when the log is above 64MB. + + + SET CHECKPOINT DEFRAG 32; + Sets the threshold in percentage for performing a DEFRAG during a checkpoint. + + + + + From b88bdb37c92f4e5eb5cd833a20f73debc5291211 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20Thomas?= Date: Fri, 8 Mar 2019 23:37:41 +0100 Subject: [PATCH 4/9] Properly shutdown embedded HSQLDB database on exit --- .../java/org/airsonic/player/Application.java | 6 ++ .../airsonic/player/spring/TerminateBean.java | 55 +++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 airsonic-main/src/main/java/org/airsonic/player/spring/TerminateBean.java diff --git a/airsonic-main/src/main/java/org/airsonic/player/Application.java b/airsonic-main/src/main/java/org/airsonic/player/Application.java index 25857afe..1b69c429 100644 --- a/airsonic-main/src/main/java/org/airsonic/player/Application.java +++ b/airsonic-main/src/main/java/org/airsonic/player/Application.java @@ -2,6 +2,7 @@ package org.airsonic.player; import net.sf.ehcache.constructs.web.ShutdownListener; import org.airsonic.player.filter.*; +import org.airsonic.player.spring.TerminateBean; import org.directwebremoting.servlet.DwrServlet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -56,6 +57,11 @@ public class Application extends SpringBootServletInitializer implements Embedde return servlet; } + @Bean + public TerminateBean terminateBean() { + return new TerminateBean(); + } + @Bean public ServletRegistrationBean cxfServletBean() { return new ServletRegistrationBean(new org.apache.cxf.transport.servlet.CXFServlet(), "/ws/*"); diff --git a/airsonic-main/src/main/java/org/airsonic/player/spring/TerminateBean.java b/airsonic-main/src/main/java/org/airsonic/player/spring/TerminateBean.java new file mode 100644 index 00000000..9c6e83f4 --- /dev/null +++ b/airsonic-main/src/main/java/org/airsonic/player/spring/TerminateBean.java @@ -0,0 +1,55 @@ +package org.airsonic.player.spring; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.datasource.DataSourceUtils; + +import javax.annotation.PreDestroy; +import javax.sql.DataSource; + +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.SQLException; + +public class TerminateBean { + + private static final Logger LOG = LoggerFactory.getLogger(TerminateBean.class); + + @Autowired + private ApplicationContext context; + + @PreDestroy + public void onDestroy() { + Connection conn = null; + try { + // Connect to the database and retrieve the db name and version + JdbcTemplate jdbcTemplate = new JdbcTemplate(this.context.getBean(DataSource.class)); + conn = DataSourceUtils.getConnection(jdbcTemplate.getDataSource()); + DatabaseMetaData meta = conn.getMetaData(); + String productName = meta.getDatabaseProductName(); + int productVersion = meta.getDatabaseMajorVersion(); + + // Properly shutdown HSQLDB databases + if (productName.equals("HSQL Database Engine") && (productVersion == 1 || productVersion == 2)) { + LOG.info("Database shutdown in progress..."); + conn.setAutoCommit(true); + jdbcTemplate.execute("SHUTDOWN"); + LOG.info("Database shutdown complete."); + } + + } catch (SQLException e) { + e.printStackTrace(); + + } finally { + try { + if(conn != null) + conn.close(); + } catch(Exception ex) { + ex.printStackTrace(); + } + } + } +} From 76e8abd219c36d128b2c78245fb2d484d94816b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20Thomas?= Date: Sat, 9 Mar 2019 13:24:58 +0100 Subject: [PATCH 5/9] Move HSQLDB checkpoint/shutdown to a bean specific to the legacy profile --- .../java/org/airsonic/player/Application.java | 6 -- .../org/airsonic/player/dao/DaoHelper.java | 4 +- .../airsonic/player/dao/GenericDaoHelper.java | 35 ----------- .../player/dao/LegacyHsqlDaoHelper.java | 60 +++++++++++++++++++ .../airsonic/player/spring/TerminateBean.java | 55 ----------------- .../applicationContext-db-legacy.xml | 10 +++- .../main/resources/applicationContext-db.xml | 14 ++--- 7 files changed, 77 insertions(+), 107 deletions(-) create mode 100644 airsonic-main/src/main/java/org/airsonic/player/dao/LegacyHsqlDaoHelper.java delete mode 100644 airsonic-main/src/main/java/org/airsonic/player/spring/TerminateBean.java diff --git a/airsonic-main/src/main/java/org/airsonic/player/Application.java b/airsonic-main/src/main/java/org/airsonic/player/Application.java index 1b69c429..25857afe 100644 --- a/airsonic-main/src/main/java/org/airsonic/player/Application.java +++ b/airsonic-main/src/main/java/org/airsonic/player/Application.java @@ -2,7 +2,6 @@ package org.airsonic.player; import net.sf.ehcache.constructs.web.ShutdownListener; import org.airsonic.player.filter.*; -import org.airsonic.player.spring.TerminateBean; import org.directwebremoting.servlet.DwrServlet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -57,11 +56,6 @@ public class Application extends SpringBootServletInitializer implements Embedde return servlet; } - @Bean - public TerminateBean terminateBean() { - return new TerminateBean(); - } - @Bean public ServletRegistrationBean cxfServletBean() { return new ServletRegistrationBean(new org.apache.cxf.transport.servlet.CXFServlet(), "/ws/*"); diff --git a/airsonic-main/src/main/java/org/airsonic/player/dao/DaoHelper.java b/airsonic-main/src/main/java/org/airsonic/player/dao/DaoHelper.java index 5a5c2a84..5590b5cf 100644 --- a/airsonic-main/src/main/java/org/airsonic/player/dao/DaoHelper.java +++ b/airsonic-main/src/main/java/org/airsonic/player/dao/DaoHelper.java @@ -53,7 +53,7 @@ public interface DaoHelper { * Database checkpoints will make sure that the database is written on the disk * and optimize on-disk storage. * - * @return true if the checkpoint succeeded + * @return true if the checkpoint succeeded, false otherwise */ - public boolean checkpoint(); + public default boolean checkpoint() { return false; } } diff --git a/airsonic-main/src/main/java/org/airsonic/player/dao/GenericDaoHelper.java b/airsonic-main/src/main/java/org/airsonic/player/dao/GenericDaoHelper.java index 513ee03f..32528607 100644 --- a/airsonic-main/src/main/java/org/airsonic/player/dao/GenericDaoHelper.java +++ b/airsonic-main/src/main/java/org/airsonic/player/dao/GenericDaoHelper.java @@ -4,13 +4,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; -import org.springframework.jdbc.datasource.DataSourceUtils; import javax.sql.DataSource; -import java.sql.Connection; -import java.sql.DatabaseMetaData; - public class GenericDaoHelper implements DaoHelper { private static final Logger LOG = LoggerFactory.getLogger(GenericDaoHelper.class); @@ -43,35 +39,4 @@ public class GenericDaoHelper implements DaoHelper { public DataSource getDataSource() { return dataSource; } - - @Override - public boolean checkpoint() { - - try { - Connection conn = DataSourceUtils.getConnection(getJdbcTemplate().getDataSource()); - DatabaseMetaData meta = conn.getMetaData(); - String productName = meta.getDatabaseProductName(); - int productVersion = meta.getDatabaseMajorVersion(); - - // HSQLDB (at least version 1) does not handle automatic checkpoints very well by default. - // This makes sure the temporary log is actually written to more persistent storage. - if (productName.equals("HSQL Database Engine") && (productVersion == 1 || productVersion == 2)) { - LOG.info("Performing database checkpoint"); - getJdbcTemplate().execute("CHECKPOINT DEFRAG"); - return true; - } else { - LOG.debug("Database checkpoint not implemented for '" + productName + "'"); - return false; - } - } - - // Since this method is a best-effort operation, we don't want to show - // a message if the checkpoint failed ; just assume the operation is - // unsupported. - catch(java.sql.SQLException e) { - LOG.debug("An exception occurred during database checkpoint: " + e.toString()); - } - - return false; - } } diff --git a/airsonic-main/src/main/java/org/airsonic/player/dao/LegacyHsqlDaoHelper.java b/airsonic-main/src/main/java/org/airsonic/player/dao/LegacyHsqlDaoHelper.java new file mode 100644 index 00000000..b199a75c --- /dev/null +++ b/airsonic-main/src/main/java/org/airsonic/player/dao/LegacyHsqlDaoHelper.java @@ -0,0 +1,60 @@ +package org.airsonic.player.dao; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.datasource.DataSourceUtils; + +import javax.annotation.PreDestroy; +import javax.sql.DataSource; + +import java.sql.Connection; +import java.sql.SQLException; + +/** + * Special Dao Helper with additional features for managing the legacy embedded HSQL database. + */ +public class LegacyHsqlDaoHelper extends GenericDaoHelper { + + private static final Logger LOG = LoggerFactory.getLogger(LegacyHsqlDaoHelper.class); + + public LegacyHsqlDaoHelper(DataSource dataSource) { + super(dataSource); + } + + @Override + public boolean checkpoint() { + // HSQLDB (at least version 1) does not handle automatic checkpoints very well by default. + // This makes sure the temporary log is actually written to more persistent storage. + LOG.info("Database checkpoint in progress..."); + getJdbcTemplate().execute("CHECKPOINT DEFRAG"); + LOG.info("Database checkpoint complete."); + return true; + } + + @PreDestroy + public void onDestroy() { + Connection conn = null; + try { + // Properly shutdown the embedded HSQLDB database. + LOG.info("Database shutdown in progress..."); + JdbcTemplate jdbcTemplate = getJdbcTemplate(); + conn = DataSourceUtils.getConnection(jdbcTemplate.getDataSource()); + conn.setAutoCommit(true); + jdbcTemplate.execute("SHUTDOWN"); + LOG.info("Database shutdown complete."); + + } catch (SQLException e) { + LOG.error("Database shutdown failed: " + e); + e.printStackTrace(); + + } finally { + try { + if(conn != null) + conn.close(); + } catch(Exception ex) { + ex.printStackTrace(); + } + } + } +} diff --git a/airsonic-main/src/main/java/org/airsonic/player/spring/TerminateBean.java b/airsonic-main/src/main/java/org/airsonic/player/spring/TerminateBean.java deleted file mode 100644 index 9c6e83f4..00000000 --- a/airsonic-main/src/main/java/org/airsonic/player/spring/TerminateBean.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.airsonic.player.spring; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContext; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.datasource.DataSourceUtils; - -import javax.annotation.PreDestroy; -import javax.sql.DataSource; - -import java.sql.Connection; -import java.sql.DatabaseMetaData; -import java.sql.SQLException; - -public class TerminateBean { - - private static final Logger LOG = LoggerFactory.getLogger(TerminateBean.class); - - @Autowired - private ApplicationContext context; - - @PreDestroy - public void onDestroy() { - Connection conn = null; - try { - // Connect to the database and retrieve the db name and version - JdbcTemplate jdbcTemplate = new JdbcTemplate(this.context.getBean(DataSource.class)); - conn = DataSourceUtils.getConnection(jdbcTemplate.getDataSource()); - DatabaseMetaData meta = conn.getMetaData(); - String productName = meta.getDatabaseProductName(); - int productVersion = meta.getDatabaseMajorVersion(); - - // Properly shutdown HSQLDB databases - if (productName.equals("HSQL Database Engine") && (productVersion == 1 || productVersion == 2)) { - LOG.info("Database shutdown in progress..."); - conn.setAutoCommit(true); - jdbcTemplate.execute("SHUTDOWN"); - LOG.info("Database shutdown complete."); - } - - } catch (SQLException e) { - e.printStackTrace(); - - } finally { - try { - if(conn != null) - conn.close(); - } catch(Exception ex) { - ex.printStackTrace(); - } - } - } -} diff --git a/airsonic-main/src/main/resources/applicationContext-db-legacy.xml b/airsonic-main/src/main/resources/applicationContext-db-legacy.xml index f866f385..b933f284 100644 --- a/airsonic-main/src/main/resources/applicationContext-db-legacy.xml +++ b/airsonic-main/src/main/resources/applicationContext-db-legacy.xml @@ -6,11 +6,17 @@ - - \ No newline at end of file + + + + + + + + diff --git a/airsonic-main/src/main/resources/applicationContext-db.xml b/airsonic-main/src/main/resources/applicationContext-db.xml index c3e13b7c..de2db1ae 100644 --- a/airsonic-main/src/main/resources/applicationContext-db.xml +++ b/airsonic-main/src/main/resources/applicationContext-db.xml @@ -3,12 +3,6 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> - - - - - - @@ -17,6 +11,12 @@ + + + + + + @@ -38,4 +38,4 @@ - \ No newline at end of file + From b753e4863206dcbd7dea379cc4c8114a457a13bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20Thomas?= Date: Sat, 9 Mar 2019 13:29:44 +0100 Subject: [PATCH 6/9] Log more information when running the 'cleanup db' action --- .../player/controller/MusicFolderSettingsController.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/airsonic-main/src/main/java/org/airsonic/player/controller/MusicFolderSettingsController.java b/airsonic-main/src/main/java/org/airsonic/player/controller/MusicFolderSettingsController.java index b5a657d9..09e55a3d 100644 --- a/airsonic-main/src/main/java/org/airsonic/player/controller/MusicFolderSettingsController.java +++ b/airsonic-main/src/main/java/org/airsonic/player/controller/MusicFolderSettingsController.java @@ -26,6 +26,8 @@ import org.airsonic.player.dao.MediaFileDao; import org.airsonic.player.domain.MusicFolder; import org.airsonic.player.service.MediaScannerService; import org.airsonic.player.service.SettingsService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; @@ -48,6 +50,8 @@ import java.util.stream.Collectors; @RequestMapping("/musicFolderSettings") public class MusicFolderSettingsController { + private static final Logger LOG = LoggerFactory.getLogger(MusicFolderSettingsController.class); + @Autowired private SettingsService settingsService; @Autowired @@ -93,9 +97,14 @@ public class MusicFolderSettingsController { private void expunge() { + LOG.info("Cleaning database..."); + LOG.info("Deleting non-present artists..."); artistDao.expunge(); + LOG.info("Deleting non-present albums..."); albumDao.expunge(); + LOG.info("Deleting non-present media files..."); mediaFileDao.expunge(); + LOG.info("Database cleanup complete."); mediaFileDao.checkpoint(); } From 8c46d39569f006ce23fc86c38f86447936620f97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20Thomas?= Date: Sun, 10 Mar 2019 20:50:27 +0100 Subject: [PATCH 7/9] Do not log message about hsqldb-defrag migration on each launch The FILES DEFRAG / FILES LOG SIZE properties are kept when upgrading to 2.x; it's enough that they were set once on 1.8. For new installations the migration will still run with the correct SQL statements. --- .../liquibase/10.2/setup-hsqldb-checkpoint-defrag.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/airsonic-main/src/main/resources/liquibase/10.2/setup-hsqldb-checkpoint-defrag.xml b/airsonic-main/src/main/resources/liquibase/10.2/setup-hsqldb-checkpoint-defrag.xml index 8377af76..e62b2f71 100644 --- a/airsonic-main/src/main/resources/liquibase/10.2/setup-hsqldb-checkpoint-defrag.xml +++ b/airsonic-main/src/main/resources/liquibase/10.2/setup-hsqldb-checkpoint-defrag.xml @@ -4,7 +4,7 @@ xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd"> - + @@ -31,7 +31,7 @@ 7:890e52428bbc2a792fea1e026a4b7610 - + From 7510b04efcaaece7978abdec7fb15da261e87cf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20Thomas?= Date: Sat, 16 Mar 2019 17:28:00 +0100 Subject: [PATCH 8/9] Make checkpoint() method void (return value is not used) --- .../src/main/java/org/airsonic/player/dao/AbstractDao.java | 2 +- .../src/main/java/org/airsonic/player/dao/DaoHelper.java | 4 +--- .../java/org/airsonic/player/dao/LegacyHsqlDaoHelper.java | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/airsonic-main/src/main/java/org/airsonic/player/dao/AbstractDao.java b/airsonic-main/src/main/java/org/airsonic/player/dao/AbstractDao.java index a01836ab..757accc5 100644 --- a/airsonic-main/src/main/java/org/airsonic/player/dao/AbstractDao.java +++ b/airsonic-main/src/main/java/org/airsonic/player/dao/AbstractDao.java @@ -189,6 +189,6 @@ public class AbstractDao { this.daoHelper = daoHelper; } - public boolean checkpoint() { return daoHelper.checkpoint(); } + public void checkpoint() { daoHelper.checkpoint(); } } diff --git a/airsonic-main/src/main/java/org/airsonic/player/dao/DaoHelper.java b/airsonic-main/src/main/java/org/airsonic/player/dao/DaoHelper.java index 5590b5cf..28acc180 100644 --- a/airsonic-main/src/main/java/org/airsonic/player/dao/DaoHelper.java +++ b/airsonic-main/src/main/java/org/airsonic/player/dao/DaoHelper.java @@ -52,8 +52,6 @@ public interface DaoHelper { * * Database checkpoints will make sure that the database is written on the disk * and optimize on-disk storage. - * - * @return true if the checkpoint succeeded, false otherwise */ - public default boolean checkpoint() { return false; } + public default void checkpoint() { } } diff --git a/airsonic-main/src/main/java/org/airsonic/player/dao/LegacyHsqlDaoHelper.java b/airsonic-main/src/main/java/org/airsonic/player/dao/LegacyHsqlDaoHelper.java index b199a75c..d8d8c386 100644 --- a/airsonic-main/src/main/java/org/airsonic/player/dao/LegacyHsqlDaoHelper.java +++ b/airsonic-main/src/main/java/org/airsonic/player/dao/LegacyHsqlDaoHelper.java @@ -23,13 +23,12 @@ public class LegacyHsqlDaoHelper extends GenericDaoHelper { } @Override - public boolean checkpoint() { + public void checkpoint() { // HSQLDB (at least version 1) does not handle automatic checkpoints very well by default. // This makes sure the temporary log is actually written to more persistent storage. LOG.info("Database checkpoint in progress..."); getJdbcTemplate().execute("CHECKPOINT DEFRAG"); LOG.info("Database checkpoint complete."); - return true; } @PreDestroy From 2c1b5205e8d99999e3f25f3513359830250224fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20Thomas?= Date: Sat, 16 Mar 2019 17:30:43 +0100 Subject: [PATCH 9/9] Write new db maintenance logs as 'debug' instead of 'info' --- .../player/controller/MusicFolderSettingsController.java | 2 +- .../java/org/airsonic/player/dao/LegacyHsqlDaoHelper.java | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/airsonic-main/src/main/java/org/airsonic/player/controller/MusicFolderSettingsController.java b/airsonic-main/src/main/java/org/airsonic/player/controller/MusicFolderSettingsController.java index 09e55a3d..1895e0a6 100644 --- a/airsonic-main/src/main/java/org/airsonic/player/controller/MusicFolderSettingsController.java +++ b/airsonic-main/src/main/java/org/airsonic/player/controller/MusicFolderSettingsController.java @@ -104,7 +104,7 @@ public class MusicFolderSettingsController { albumDao.expunge(); LOG.info("Deleting non-present media files..."); mediaFileDao.expunge(); - LOG.info("Database cleanup complete."); + LOG.debug("Database cleanup complete."); mediaFileDao.checkpoint(); } diff --git a/airsonic-main/src/main/java/org/airsonic/player/dao/LegacyHsqlDaoHelper.java b/airsonic-main/src/main/java/org/airsonic/player/dao/LegacyHsqlDaoHelper.java index d8d8c386..e6648c23 100644 --- a/airsonic-main/src/main/java/org/airsonic/player/dao/LegacyHsqlDaoHelper.java +++ b/airsonic-main/src/main/java/org/airsonic/player/dao/LegacyHsqlDaoHelper.java @@ -26,9 +26,9 @@ public class LegacyHsqlDaoHelper extends GenericDaoHelper { public void checkpoint() { // HSQLDB (at least version 1) does not handle automatic checkpoints very well by default. // This makes sure the temporary log is actually written to more persistent storage. - LOG.info("Database checkpoint in progress..."); + LOG.debug("Database checkpoint in progress..."); getJdbcTemplate().execute("CHECKPOINT DEFRAG"); - LOG.info("Database checkpoint complete."); + LOG.debug("Database checkpoint complete."); } @PreDestroy @@ -36,12 +36,12 @@ public class LegacyHsqlDaoHelper extends GenericDaoHelper { Connection conn = null; try { // Properly shutdown the embedded HSQLDB database. - LOG.info("Database shutdown in progress..."); + LOG.debug("Database shutdown in progress..."); JdbcTemplate jdbcTemplate = getJdbcTemplate(); conn = DataSourceUtils.getConnection(jdbcTemplate.getDataSource()); conn.setAutoCommit(true); jdbcTemplate.execute("SHUTDOWN"); - LOG.info("Database shutdown complete."); + LOG.debug("Database shutdown complete."); } catch (SQLException e) { LOG.error("Database shutdown failed: " + e);