Merge remote-tracking branch 'airsonic/pr/895'

master
Andrew DeMaria 6 years ago
commit 360f469bf1
No known key found for this signature in database
GPG Key ID: 0A3F5E91F8364EDF
  1. 10
      airsonic-main/src/main/java/org/airsonic/player/controller/MusicFolderSettingsController.java
  2. 2
      airsonic-main/src/main/java/org/airsonic/player/dao/AbstractDao.java
  3. 8
      airsonic-main/src/main/java/org/airsonic/player/dao/DaoHelper.java
  4. 4
      airsonic-main/src/main/java/org/airsonic/player/dao/GenericDaoHelper.java
  5. 59
      airsonic-main/src/main/java/org/airsonic/player/dao/LegacyHsqlDaoHelper.java
  6. 1
      airsonic-main/src/main/java/org/airsonic/player/service/MediaScannerService.java
  7. 8
      airsonic-main/src/main/resources/applicationContext-db-legacy.xml
  8. 12
      airsonic-main/src/main/resources/applicationContext-db.xml
  9. 32
      airsonic-main/src/main/resources/liquibase/10.2/setup-hsqldb-checkpoint-defrag.xml

@ -26,6 +26,8 @@ import org.airsonic.player.dao.MediaFileDao;
import org.airsonic.player.domain.MusicFolder; import org.airsonic.player.domain.MusicFolder;
import org.airsonic.player.service.MediaScannerService; import org.airsonic.player.service.MediaScannerService;
import org.airsonic.player.service.SettingsService; import org.airsonic.player.service.SettingsService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
@ -48,6 +50,8 @@ import java.util.stream.Collectors;
@RequestMapping("/musicFolderSettings") @RequestMapping("/musicFolderSettings")
public class MusicFolderSettingsController { public class MusicFolderSettingsController {
private static final Logger LOG = LoggerFactory.getLogger(MusicFolderSettingsController.class);
@Autowired @Autowired
private SettingsService settingsService; private SettingsService settingsService;
@Autowired @Autowired
@ -93,9 +97,15 @@ public class MusicFolderSettingsController {
private void expunge() { private void expunge() {
LOG.info("Cleaning database...");
LOG.info("Deleting non-present artists...");
artistDao.expunge(); artistDao.expunge();
LOG.info("Deleting non-present albums...");
albumDao.expunge(); albumDao.expunge();
LOG.info("Deleting non-present media files...");
mediaFileDao.expunge(); mediaFileDao.expunge();
LOG.debug("Database cleanup complete.");
mediaFileDao.checkpoint();
} }
private List<MusicFolderSettingsCommand.MusicFolderInfo> wrap(List<MusicFolder> musicFolders) { private List<MusicFolderSettingsCommand.MusicFolderInfo> wrap(List<MusicFolder> musicFolders) {

@ -189,4 +189,6 @@ public class AbstractDao {
this.daoHelper = daoHelper; this.daoHelper = daoHelper;
} }
public void checkpoint() { daoHelper.checkpoint(); }
} }

@ -46,4 +46,12 @@ public interface DaoHelper {
NamedParameterJdbcTemplate getNamedParameterJdbcTemplate(); NamedParameterJdbcTemplate getNamedParameterJdbcTemplate();
DataSource getDataSource(); 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.
*/
public default void checkpoint() { }
} }

@ -1,5 +1,7 @@
package org.airsonic.player.dao; package org.airsonic.player.dao;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
@ -7,6 +9,8 @@ import javax.sql.DataSource;
public class GenericDaoHelper implements DaoHelper { public class GenericDaoHelper implements DaoHelper {
private static final Logger LOG = LoggerFactory.getLogger(GenericDaoHelper.class);
final JdbcTemplate jdbcTemplate; final JdbcTemplate jdbcTemplate;
final NamedParameterJdbcTemplate namedParameterJdbcTemplate; final NamedParameterJdbcTemplate namedParameterJdbcTemplate;

@ -0,0 +1,59 @@
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 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.debug("Database checkpoint in progress...");
getJdbcTemplate().execute("CHECKPOINT DEFRAG");
LOG.debug("Database checkpoint complete.");
}
@PreDestroy
public void onDestroy() {
Connection conn = null;
try {
// Properly shutdown the embedded HSQLDB database.
LOG.debug("Database shutdown in progress...");
JdbcTemplate jdbcTemplate = getJdbcTemplate();
conn = DataSourceUtils.getConnection(jdbcTemplate.getDataSource());
conn.setAutoCommit(true);
jdbcTemplate.execute("SHUTDOWN");
LOG.debug("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();
}
}
}
}

@ -156,6 +156,7 @@ public class MediaScannerService {
public void run() { public void run() {
doScanLibrary(); doScanLibrary();
playlistService.importPlaylists(); playlistService.importPlaylists();
mediaFileDao.checkpoint();
} }
}; };

@ -6,11 +6,17 @@
<bean id="dataSource" <bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource"> class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver" /> <property name="driverClassName" value="org.hsqldb.jdbcDriver" />
<property name="url" <property name="url"
value="#{T(org.airsonic.player.service.SettingsService).defaultJDBCUrl}" /> value="#{T(org.airsonic.player.service.SettingsService).defaultJDBCUrl}" />
<property name="username" value="sa" /> <property name="username" value="sa" />
<property name="password" value="" /> <property name="password" value="" />
</bean> </bean>
<!-- Overwrite the GenericDaoHelper bean defined in applicationContext-db.xml -->
<!-- This bean is specific to the legacy embedded HSQLDB database -->
<bean id="daoHelper" class="org.airsonic.player.dao.LegacyHsqlDaoHelper">
<constructor-arg name="dataSource" ref="dataSource" />
</bean>
</beans> </beans>

@ -3,12 +3,6 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" 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"> 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">
<import resource="applicationContext-db-jndi.xml" />
<import resource="applicationContext-db-embed.xml" />
<import resource="applicationContext-db-legacy.xml" />
<tx:annotation-driven/>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<constructor-arg ref="dataSource"/> <constructor-arg ref="dataSource"/>
</bean> </bean>
@ -17,6 +11,12 @@
<constructor-arg name="dataSource" ref="dataSource" /> <constructor-arg name="dataSource" ref="dataSource" />
</bean> </bean>
<import resource="applicationContext-db-jndi.xml" />
<import resource="applicationContext-db-embed.xml" />
<import resource="applicationContext-db-legacy.xml" />
<tx:annotation-driven/>
<bean id="rollbackFile" class="java.io.File"> <bean id="rollbackFile" class="java.io.File">
<constructor-arg type="java.io.File" index="0" value="#{T(org.airsonic.player.service.SettingsService).airsonicHome}" /> <constructor-arg type="java.io.File" index="0" value="#{T(org.airsonic.player.service.SettingsService).airsonicHome}" />
<constructor-arg type="java.lang.String" index="1" value="rollback.sql" /> <constructor-arg type="java.lang.String" index="1" value="rollback.sql" />

@ -2,10 +2,40 @@
xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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"> xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
<changeSet id="setup-hsqldb-2-checkpoint-defrag" author="fxthomas">
<preConditions onFail="MARK_RAN">
<dbms type="hsqldb" />
<customPrecondition className="org.airsonic.player.spring.DbmsVersionPrecondition" >
<param name="major" value="2" />
</customPrecondition>
</preConditions>
<sql>
CHECKPOINT DEFRAG;
<comment>Defragment the database before enabling auto defrag, so that the biggest part of the work is done during migration.</comment>
</sql>
<sql>
SET FILES LOG SIZE 64;
<comment>Automatically run a CHECKPOINT when the log is above 64MB. http://hsqldb.org/doc/guide/management-chapt.html#N150AB</comment>
</sql>
<sql>
SET FILES DEFRAG 50;
<comment>Sets the threshold in percentage for performing a DEFRAG during a checkpoint. http://hsqldb.org/doc/guide/management-chapt.html#N1506D</comment>
</sql>
<rollback></rollback>
</changeSet>
<changeSet id="setup-hsqldb-checkpoint-defrag" author="fxthomas"> <changeSet id="setup-hsqldb-checkpoint-defrag" author="fxthomas">
<validCheckSum>7:890e52428bbc2a792fea1e026a4b7610</validCheckSum>
<preConditions onFail="MARK_RAN"> <preConditions onFail="MARK_RAN">
<dbms type="hsqldb" /> <dbms type="hsqldb" />
<customPrecondition className="org.airsonic.player.spring.DbmsVersionPrecondition" >
<param name="major" value="1" />
</customPrecondition>
</preConditions> </preConditions>
<sql> <sql>
@ -18,7 +48,7 @@
</sql> </sql>
<sql> <sql>
SET CHECKPOINT DEFRAG 32; SET CHECKPOINT DEFRAG 32;
<comment>Automatically defragment on CHECKPOINT when the wasted space is above 32MB.</comment> <comment>Sets the threshold in percentage for performing a DEFRAG during a checkpoint.</comment>
</sql> </sql>
<rollback></rollback> <rollback></rollback>

Loading…
Cancel
Save