From: Julien Lancelot Date: Tue, 4 Dec 2012 13:35:07 +0000 (+0100) Subject: SONAR-3306 Refactoring to use DatabaseSemaphore instead of SemaphoreDao X-Git-Tag: 3.4~189 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=cdf6262009b0245c719ffefd746a996f2f48a289;p=sonarqube.git SONAR-3306 Refactoring to use DatabaseSemaphore instead of SemaphoreDao --- diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java index 810a5aa06bf..1cbc4f387fc 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java @@ -394,7 +394,6 @@ public final class CorePlugin extends SonarPlugin { DefaultResourceTypes.class, UserManagedMetrics.class, ProjectFileSystemLogger.class, - DatabaseSemaphoreImpl.class, Periods.class, // maven diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/DatabaseSemaphoreImpl.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/DatabaseSemaphoreImpl.java deleted file mode 100644 index 813a679bce9..00000000000 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/DatabaseSemaphoreImpl.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Sonar, open source software quality management tool. - * Copyright (C) 2008-2012 SonarSource - * mailto:contact AT sonarsource DOT com - * - * Sonar is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * Sonar is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with Sonar; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 - */ -package org.sonar.plugins.core; - -import org.sonar.api.utils.DatabaseSemaphore; -import org.sonar.core.persistence.SemaphoreDao; - -/** - * @since 3.4 - */ -public class DatabaseSemaphoreImpl implements DatabaseSemaphore { - - private SemaphoreDao dao; - - public DatabaseSemaphoreImpl(SemaphoreDao dao) { - this.dao = dao; - } - - public boolean acquire(String name, int maxDurationInSeconds) { - return dao.acquire(name, maxDurationInSeconds).isAcquired(); - } - - public void release(String name) { - dao.release(name); - } -} diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/DatabaseSemaphoreImplTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/DatabaseSemaphoreImplTest.java deleted file mode 100644 index e4f99459d67..00000000000 --- a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/DatabaseSemaphoreImplTest.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Sonar, open source software quality management tool. - * Copyright (C) 2008-2012 SonarSource - * mailto:contact AT sonarsource DOT com - * - * Sonar is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * Sonar is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with Sonar; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 - */ -package org.sonar.plugins.core; - -import org.junit.Test; -import org.sonar.core.persistence.Lock; -import org.sonar.core.persistence.SemaphoreDao; - -import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -public class DatabaseSemaphoreImplTest { - - @Test - public void should_be_a_bridge_over_dao() { - Lock lock = mock(Lock.class); - SemaphoreDao dao = mock(SemaphoreDao.class); - when(dao.acquire(anyString(), anyInt())).thenReturn(lock); - - DatabaseSemaphoreImpl impl = new DatabaseSemaphoreImpl(dao); - - impl.acquire("do-xxx", 50000); - verify(dao).acquire("do-xxx", 50000); - - impl.release("do-xxx"); - verify(dao).release("do-xxx"); - } -} diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchModule.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchModule.java index 949030df4f6..3067a161cda 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchModule.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchModule.java @@ -48,6 +48,7 @@ import org.sonar.core.i18n.RuleI18nManager; import org.sonar.core.metric.CacheMetricFinder; import org.sonar.core.notification.DefaultNotificationManager; import org.sonar.core.persistence.DaoUtils; +import org.sonar.core.persistence.DatabaseSemaphoreImpl; import org.sonar.core.persistence.DatabaseVersion; import org.sonar.core.persistence.MyBatis; import org.sonar.core.resource.DefaultResourcePermissions; @@ -103,6 +104,7 @@ public class BatchModule extends Module { container.addSingleton(DefaultUserFinder.class); container.addSingleton(ResourceTypes.class); container.addSingleton(MetricProvider.class); + container.addSingleton(DatabaseSemaphoreImpl.class); container.addSingleton(CheckSemaphore.class); } diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/CheckSemaphore.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/CheckSemaphore.java index 7ea91681fe3..9bc4b65e621 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/CheckSemaphore.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/CheckSemaphore.java @@ -24,21 +24,22 @@ import org.slf4j.LoggerFactory; import org.sonar.api.CoreProperties; import org.sonar.api.config.Settings; import org.sonar.api.resources.Project; +import org.sonar.api.utils.DatabaseSemaphore; import org.sonar.api.utils.SonarException; import org.sonar.batch.ProjectTree; -import org.sonar.core.persistence.Lock; -import org.sonar.core.persistence.SemaphoreDao; + +import static org.sonar.api.utils.DatabaseSemaphore.Lock; public class CheckSemaphore { private static final Logger LOG = LoggerFactory.getLogger(CheckSemaphore.class); - private final SemaphoreDao semaphoreDao; + private final DatabaseSemaphore databaseSemaphore; private final ProjectTree projectTree; private final Settings settings; - public CheckSemaphore(SemaphoreDao semaphoreDao, ProjectTree projectTree, Settings settings) { - this.semaphoreDao = semaphoreDao; + public CheckSemaphore(DatabaseSemaphore databaseSemaphore, ProjectTree projectTree, Settings settings) { + this.databaseSemaphore = databaseSemaphore; this.projectTree = projectTree; this.settings = settings; } @@ -72,15 +73,16 @@ public class CheckSemaphore { private Lock acquire() { LOG.debug("Acquire semaphore on project : {}, with key {}", getProject(), getSemaphoreKey()); if (!isForceAnalyseActivated()) { - return semaphoreDao.acquire(getSemaphoreKey()); + return databaseSemaphore.acquire(getSemaphoreKey()); } else { - return semaphoreDao.acquire(getSemaphoreKey(), 0); + // In force mode, we acquire the lock regardless there's a existing lock or not + return databaseSemaphore.acquire(getSemaphoreKey(), 0); } } private void release() { LOG.debug("Release semaphore on project : {}, with key {}", getProject(), getSemaphoreKey()); - semaphoreDao.release(getSemaphoreKey()); + databaseSemaphore.release(getSemaphoreKey()); } private String getSemaphoreKey() { diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/CheckSemaphoreTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/CheckSemaphoreTest.java index d003336713e..e3d09868d9a 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/CheckSemaphoreTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/CheckSemaphoreTest.java @@ -24,10 +24,9 @@ import org.junit.Test; import org.sonar.api.CoreProperties; import org.sonar.api.config.Settings; import org.sonar.api.resources.Project; +import org.sonar.api.utils.DatabaseSemaphore; import org.sonar.api.utils.SonarException; import org.sonar.batch.ProjectTree; -import org.sonar.core.persistence.Lock; -import org.sonar.core.persistence.SemaphoreDao; import java.util.Date; @@ -37,12 +36,13 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static org.sonar.api.utils.DatabaseSemaphore.Lock; public class CheckSemaphoreTest { private CheckSemaphore checkSemaphore; - private SemaphoreDao semaphoreDao; + private DatabaseSemaphore databaseSemaphore; private ProjectTree projectTree; private Settings settings; @@ -53,9 +53,9 @@ public class CheckSemaphoreTest { public void setUp() { lock = mock(Lock.class); - semaphoreDao = mock(SemaphoreDao.class); - when(semaphoreDao.acquire(anyString())).thenReturn(lock); - when(semaphoreDao.acquire(anyString(), anyInt())).thenReturn(lock); + databaseSemaphore = mock(DatabaseSemaphore.class); + when(databaseSemaphore.acquire(anyString())).thenReturn(lock); + when(databaseSemaphore.acquire(anyString(), anyInt())).thenReturn(lock); projectTree = mock(ProjectTree.class); settings = new Settings(); @@ -65,7 +65,7 @@ public class CheckSemaphoreTest { project = new Project("key", "branch", "name"); when(projectTree.getRootProject()).thenReturn(project); - checkSemaphore = new CheckSemaphore(semaphoreDao, projectTree, settings); + checkSemaphore = new CheckSemaphore(databaseSemaphore, projectTree, settings); } @Test @@ -73,7 +73,7 @@ public class CheckSemaphoreTest { when(lock.isAcquired()).thenReturn(true); checkSemaphore.start(); - verify(semaphoreDao).acquire(anyString()); + verify(databaseSemaphore).acquire(anyString()); } @Test @@ -84,7 +84,7 @@ public class CheckSemaphoreTest { when(lock.isAcquired()).thenReturn(true); checkSemaphore.start(); - verify(semaphoreDao).acquire("batch-key"); + verify(databaseSemaphore).acquire("batch-key"); } @Test @@ -92,7 +92,7 @@ public class CheckSemaphoreTest { when(lock.isAcquired()).thenReturn(true); checkSemaphore.start(); - verify(semaphoreDao).acquire("batch-key:branch"); + verify(databaseSemaphore).acquire("batch-key:branch"); } @Test @@ -100,7 +100,7 @@ public class CheckSemaphoreTest { setForceMode(true); when(lock.isAcquired()).thenReturn(true); checkSemaphore.start(); - verify(semaphoreDao).acquire(anyString(), anyInt()); + verify(databaseSemaphore).acquire(anyString(), anyInt()); } @Test(expected = SonarException.class) @@ -108,7 +108,7 @@ public class CheckSemaphoreTest { when(lock.getLocketAt()).thenReturn(new Date()); when(lock.isAcquired()).thenReturn(false); checkSemaphore.start(); - verify(semaphoreDao, never()).acquire(anyString()); + verify(databaseSemaphore, never()).acquire(anyString()); } @Test @@ -116,21 +116,21 @@ public class CheckSemaphoreTest { setDryRunMode(true); settings = new Settings().setProperty(CoreProperties.DRY_RUN, true); checkSemaphore.start(); - verify(semaphoreDao, never()).acquire(anyString()); - verify(semaphoreDao, never()).acquire(anyString(), anyInt()); + verify(databaseSemaphore, never()).acquire(anyString()); + verify(databaseSemaphore, never()).acquire(anyString(), anyInt()); } @Test public void shouldReleaseSemaphore() { checkSemaphore.stop(); - verify(semaphoreDao).release(anyString()); + verify(databaseSemaphore).release(anyString()); } @Test public void shouldNotReleaseSemaphoreInDryRunMode() { setDryRunMode(true); checkSemaphore.stop(); - verify(semaphoreDao, never()).release(anyString()); + verify(databaseSemaphore, never()).release(anyString()); } private void setDryRunMode(boolean isInDryRunMode) { diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/DatabaseSemaphoreImpl.java b/sonar-core/src/main/java/org/sonar/core/persistence/DatabaseSemaphoreImpl.java new file mode 100644 index 00000000000..75a5bb7e2ed --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/core/persistence/DatabaseSemaphoreImpl.java @@ -0,0 +1,46 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * Sonar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.core.persistence; + +import org.sonar.api.utils.DatabaseSemaphore; + +/** + * @since 3.4 + */ +public class DatabaseSemaphoreImpl implements DatabaseSemaphore { + + private SemaphoreDao dao; + + public DatabaseSemaphoreImpl(SemaphoreDao dao) { + this.dao = dao; + } + + public Lock acquire(String name, int maxDurationInSeconds) { + return dao.acquire(name, maxDurationInSeconds); + } + + public Lock acquire(String name) { + return dao.acquire(name); + } + + public void release(String name) { + dao.release(name); + } +} diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/Lock.java b/sonar-core/src/main/java/org/sonar/core/persistence/Lock.java deleted file mode 100644 index 1e47fbcba2e..00000000000 --- a/sonar-core/src/main/java/org/sonar/core/persistence/Lock.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Sonar, open source software quality management tool. - * Copyright (C) 2008-2012 SonarSource - * mailto:contact AT sonarsource DOT com - * - * Sonar is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * Sonar is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with Sonar; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 - */ - -package org.sonar.core.persistence; - -import java.util.Date; - -/** - * @since 3.4 - */ -public class Lock { - - private String name; - private boolean acquired; - private Date locketAt; - private Date createdAt; - private Date updatedAt; - private Long durationSinceLocked; - - public Lock(String name, boolean acquired, Date locketAt, Date createdAt, Date updatedAt) { - this.name = name; - this.acquired = acquired; - this.locketAt = locketAt; - this.createdAt = createdAt; - this.updatedAt = updatedAt; - } - - public String getName() { - return name; - } - - public Date getLocketAt() { - return locketAt; - } - - public Date getCreatedAt() { - return createdAt; - } - - public Date getUpdatedAt() { - return updatedAt; - } - - public boolean isAcquired() { - return acquired; - } - - public Long getDurationSinceLocked() { - return durationSinceLocked; - } - - public void setDurationSinceLocked(Long durationSinceLocked) { - this.durationSinceLocked = durationSinceLocked; - } -} diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/SemaphoreDao.java b/sonar-core/src/main/java/org/sonar/core/persistence/SemaphoreDao.java index 12100acf19a..471315c2d40 100644 --- a/sonar-core/src/main/java/org/sonar/core/persistence/SemaphoreDao.java +++ b/sonar-core/src/main/java/org/sonar/core/persistence/SemaphoreDao.java @@ -26,6 +26,8 @@ import org.apache.ibatis.session.SqlSession; import java.util.Date; +import static org.sonar.api.utils.DatabaseSemaphore.Lock; + /** * @since 3.4 */ diff --git a/sonar-core/src/test/java/org/sonar/core/persistence/DatabaseSemaphoreImplTest.java b/sonar-core/src/test/java/org/sonar/core/persistence/DatabaseSemaphoreImplTest.java new file mode 100644 index 00000000000..73a7d61396b --- /dev/null +++ b/sonar-core/src/test/java/org/sonar/core/persistence/DatabaseSemaphoreImplTest.java @@ -0,0 +1,50 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * Sonar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.core.persistence; + +import org.junit.Test; + +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.sonar.api.utils.DatabaseSemaphore.Lock; + +public class DatabaseSemaphoreImplTest { + + @Test + public void should_be_a_bridge_over_dao() { + Lock lock = mock(Lock.class); + SemaphoreDao dao = mock(SemaphoreDao.class); + when(dao.acquire(anyString(), anyInt())).thenReturn(lock); + + DatabaseSemaphoreImpl impl = new DatabaseSemaphoreImpl(dao); + + impl.acquire("do-xxx", 50000); + verify(dao).acquire("do-xxx", 50000); + + impl.acquire("do-xxx"); + verify(dao).acquire("do-xxx"); + + impl.release("do-xxx"); + verify(dao).release("do-xxx"); + } +} diff --git a/sonar-core/src/test/java/org/sonar/core/persistence/SemaphoreDaoTest.java b/sonar-core/src/test/java/org/sonar/core/persistence/SemaphoreDaoTest.java index 75582e650b1..948afed4a59 100644 --- a/sonar-core/src/test/java/org/sonar/core/persistence/SemaphoreDaoTest.java +++ b/sonar-core/src/test/java/org/sonar/core/persistence/SemaphoreDaoTest.java @@ -32,6 +32,7 @@ import java.util.concurrent.CyclicBarrier; import java.util.concurrent.atomic.AtomicInteger; import static org.fest.assertions.Assertions.assertThat; +import static org.sonar.api.utils.DatabaseSemaphore.Lock; public class SemaphoreDaoTest extends AbstractDaoTestCase { diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/utils/DatabaseSemaphore.java b/sonar-plugin-api/src/main/java/org/sonar/api/utils/DatabaseSemaphore.java index f01a6e6f25f..888647c79cd 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/utils/DatabaseSemaphore.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/utils/DatabaseSemaphore.java @@ -22,6 +22,8 @@ package org.sonar.api.utils; import org.sonar.api.BatchComponent; import org.sonar.api.ServerComponent; +import java.util.Date; + /** * A semaphore shared among all the processes that can connect to the central database. * @@ -29,8 +31,77 @@ import org.sonar.api.ServerComponent; */ public interface DatabaseSemaphore extends BatchComponent, ServerComponent { - boolean acquire(String name, int maxDurationInSeconds); + /** + * Try to acquire a lock on a name, for a given duration. + * The lock will be acquired if there's no existing lock on this name or if a lock exists but the max duration is reached. + * + * @param name the key of the semaphore + * @param maxDurationInSeconds the max duration in seconds the semaphore will be acquired (a value of zero can be used to always acquire a lock) + * @return a lock containing information if the lock could be acquired or not, the duration since locked, etc. + */ + Lock acquire(String name, int maxDurationInSeconds); + + /** + * Try to acquire the lock on a name. + * The lock will be acquired only if there's no existing lock. + * + * @param name the key of the semaphore + * @return a lock containing information if the lock could be acquired or not, the duration since locked, etc. + */ + Lock acquire(String name); + /** + * Release the lock on a semaphore by its name. + * + * @param name the key of the semaphore + */ void release(String name); + static class Lock { + + private String name; + private boolean acquired; + private Date locketAt; + private Date createdAt; + private Date updatedAt; + private Long durationSinceLocked; + + public Lock(String name, boolean acquired, Date locketAt, Date createdAt, Date updatedAt) { + this.name = name; + this.acquired = acquired; + this.locketAt = locketAt; + this.createdAt = createdAt; + this.updatedAt = updatedAt; + } + + public String getName() { + return name; + } + + public Date getLocketAt() { + return locketAt; + } + + public Date getCreatedAt() { + return createdAt; + } + + public Date getUpdatedAt() { + return updatedAt; + } + + public boolean isAcquired() { + return acquired; + } + + public Long getDurationSinceLocked() { + return durationSinceLocked; + } + + public void setDurationSinceLocked(Long durationSinceLocked) { + this.durationSinceLocked = durationSinceLocked; + } + + } + }