From cdf6262009b0245c719ffefd746a996f2f48a289 Mon Sep 17 00:00:00 2001 From: Julien Lancelot Date: Tue, 4 Dec 2012 14:35:07 +0100 Subject: [PATCH] SONAR-3306 Refactoring to use DatabaseSemaphore instead of SemaphoreDao --- .../org/sonar/plugins/core/CorePlugin.java | 1 - .../sonar/batch/bootstrap/BatchModule.java | 2 + .../sonar/batch/bootstrap/CheckSemaphore.java | 18 +++-- .../batch/bootstrap/CheckSemaphoreTest.java | 32 ++++---- .../persistence}/DatabaseSemaphoreImpl.java | 11 ++- .../java/org/sonar/core/persistence/Lock.java | 72 ------------------ .../sonar/core/persistence/SemaphoreDao.java | 2 + .../DatabaseSemaphoreImplTest.java | 8 +- .../core/persistence/SemaphoreDaoTest.java | 1 + .../sonar/api/utils/DatabaseSemaphore.java | 73 ++++++++++++++++++- 10 files changed, 115 insertions(+), 105 deletions(-) rename {plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core => sonar-core/src/main/java/org/sonar/core/persistence}/DatabaseSemaphoreImpl.java (83%) delete mode 100644 sonar-core/src/main/java/org/sonar/core/persistence/Lock.java rename {plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core => sonar-core/src/test/java/org/sonar/core/persistence}/DatabaseSemaphoreImplTest.java (90%) 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/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/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/DatabaseSemaphoreImpl.java b/sonar-core/src/main/java/org/sonar/core/persistence/DatabaseSemaphoreImpl.java similarity index 83% rename from plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/DatabaseSemaphoreImpl.java rename to sonar-core/src/main/java/org/sonar/core/persistence/DatabaseSemaphoreImpl.java index 813a679bce9..75a5bb7e2ed 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/DatabaseSemaphoreImpl.java +++ b/sonar-core/src/main/java/org/sonar/core/persistence/DatabaseSemaphoreImpl.java @@ -17,10 +17,9 @@ * 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; +package org.sonar.core.persistence; import org.sonar.api.utils.DatabaseSemaphore; -import org.sonar.core.persistence.SemaphoreDao; /** * @since 3.4 @@ -33,8 +32,12 @@ public class DatabaseSemaphoreImpl implements DatabaseSemaphore { this.dao = dao; } - public boolean acquire(String name, int maxDurationInSeconds) { - return dao.acquire(name, maxDurationInSeconds).isAcquired(); + 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) { 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/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/DatabaseSemaphoreImplTest.java b/sonar-core/src/test/java/org/sonar/core/persistence/DatabaseSemaphoreImplTest.java similarity index 90% rename from plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/DatabaseSemaphoreImplTest.java rename to sonar-core/src/test/java/org/sonar/core/persistence/DatabaseSemaphoreImplTest.java index e4f99459d67..73a7d61396b 100644 --- a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/DatabaseSemaphoreImplTest.java +++ b/sonar-core/src/test/java/org/sonar/core/persistence/DatabaseSemaphoreImplTest.java @@ -17,17 +17,16 @@ * 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; +package org.sonar.core.persistence; 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; +import static org.sonar.api.utils.DatabaseSemaphore.Lock; public class DatabaseSemaphoreImplTest { @@ -42,6 +41,9 @@ public class DatabaseSemaphoreImplTest { 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; + } + + } + } -- 2.39.5