]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-3887 add org.sonar.api.utils.DatabaseSemaphore
authorSimon Brandhof <simon.brandhof@gmail.com>
Fri, 19 Oct 2012 09:02:02 +0000 (11:02 +0200)
committerSimon Brandhof <simon.brandhof@gmail.com>
Fri, 19 Oct 2012 09:02:02 +0000 (11:02 +0200)
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/DatabaseSemaphoreImpl.java [new file with mode: 0644]
plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/DatabaseSemaphoreImplTest.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/persistence/SemaphoreDao.java
sonar-core/src/main/java/org/sonar/core/persistence/SemaphoreMapper.java
sonar-core/src/main/resources/org/sonar/core/persistence/SemaphoreMapper.xml
sonar-core/src/test/java/org/sonar/core/persistence/SemaphoreDaoTest.java
sonar-plugin-api/src/main/java/org/sonar/api/utils/DatabaseSemaphore.java [new file with mode: 0644]

index 074d8d3873eb1f6a1b7c4f7b4237af58ea6ec1a1..cce3cd6870cbecd9cb85301a7a125dc2045c8916 100644 (file)
@@ -374,11 +374,12 @@ import java.util.List;
 public final class CorePlugin extends SonarPlugin {
 
   @SuppressWarnings("unchecked")
-  public List<Class<? extends Extension>> getExtensions() {
+  public List getExtensions() {
     return ImmutableList.of(
         DefaultResourceTypes.class,
         UserManagedMetrics.class,
         ProjectFileSystemLogger.class,
+        DatabaseSemaphoreImpl.class,
 
         // maven
         MavenInitializer.class,
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
new file mode 100644 (file)
index 0000000..5c992b4
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * 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);
+  }
+
+  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
new file mode 100644 (file)
index 0000000..c640159
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * 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.SemaphoreDao;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+public class DatabaseSemaphoreImplTest {
+
+  @Test
+  public void should_be_a_bridge_over_dao() {
+    SemaphoreDao dao = mock(SemaphoreDao.class);
+    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");
+  }
+}
index 2519823fadc8cd268ea6bc586508299868cf6410..fd92ccc3a0f782af999a724d47fa5acd2ddc0c93 100644 (file)
@@ -37,34 +37,34 @@ public class SemaphoreDao {
     this.mybatis = mybatis;
   }
 
-  public boolean lock(String name, int durationInSeconds) {
+  public boolean acquire(String name, int maxDurationInSeconds) {
     Preconditions.checkArgument(!Strings.isNullOrEmpty(name), "Semaphore name must not be empty");
-    Preconditions.checkArgument(durationInSeconds > 0, "Semaphore duration must be positive");
+    Preconditions.checkArgument(maxDurationInSeconds > 0, "Semaphore max duration must be positive");
 
     SqlSession session = mybatis.openSession();
     try {
       SemaphoreMapper mapper = session.getMapper(SemaphoreMapper.class);
       initialize(name, session, mapper);
-      return doLock(name, durationInSeconds, session, mapper);
+      return doAcquire(name, maxDurationInSeconds, session, mapper);
     } finally {
       MyBatis.closeQuietly(session);
     }
   }
 
-  public void unlock(String name) {
+  public void release(String name) {
     Preconditions.checkArgument(!Strings.isNullOrEmpty(name), "Semaphore name must not be empty");
     SqlSession session = mybatis.openSession();
     try {
-      session.getMapper(SemaphoreMapper.class).unlock(name);
+      session.getMapper(SemaphoreMapper.class).release(name);
       session.commit();
     } finally {
       MyBatis.closeQuietly(session);
     }
   }
 
-  private boolean doLock(String name, int durationInSeconds, SqlSession session, SemaphoreMapper mapper) {
+  private boolean doAcquire(String name, int durationInSeconds, SqlSession session, SemaphoreMapper mapper) {
     Date lockedBefore = DateUtils.addSeconds(mapper.now(), -durationInSeconds);
-    boolean ok = mapper.lock(name, lockedBefore) == 1;
+    boolean ok = mapper.acquire(name, lockedBefore) == 1;
     session.commit();
     return ok;
   }
index a2be689e1c6d472905cd028dddda9c7fa0534eb2..d77e8cd3c3fcf881137d058cdc2bcd56faa4f0e3 100644 (file)
@@ -27,9 +27,9 @@ public interface SemaphoreMapper {
 
   int initialize(@Param("name") String name, @Param("lockedAt") Date lockedAt);
 
-  int lock(@Param("name") String name, @Param("lockedBefore") Date lockedBefore);
+  int acquire(@Param("name") String name, @Param("lockedBefore") Date lockedBefore);
 
   Date now();
 
-  void unlock(String name);
+  void release(String name);
 }
index df8dac1d12439783bddee4940c0d5f1613ea15df..ea5f9f1102bd2d904d2bb2c723611c4a89252ef9 100644 (file)
     select current_timestamp
   </select>
 
-  <update id="lock" parameterType="map">
+  <update id="acquire" parameterType="map">
     update semaphores
     set updated_at = current_timestamp, locked_at = current_timestamp
     where name=#{name}
     AND locked_at &lt; #{lockedBefore}
   </update>
 
-  <delete id="unlock" parameterType="String">
+  <delete id="release" parameterType="String">
     delete from semaphores where name=#{id}
   </delete>
 
index 46617b2830bae215d00a0fec8aef518969e00244..6abc912b896e209d0e76b0120cdcf05c8bdad20f 100644 (file)
@@ -36,9 +36,9 @@ import static org.fest.assertions.Assertions.assertThat;
 public class SemaphoreDaoTest extends AbstractDaoTestCase {
 
   @Test
-  public void create_and_lock_semaphore() throws Exception {
+  public void create_and_acquire_semaphore() throws Exception {
     SemaphoreDao dao = new SemaphoreDao(getMyBatis());
-    assertThat(dao.lock("foo", 60)).isTrue();
+    assertThat(dao.acquire("foo", 60)).isTrue();
 
     Semaphore semaphore = selectSemaphore("foo");
     assertThat(semaphore).isNotNull();
@@ -47,7 +47,7 @@ public class SemaphoreDaoTest extends AbstractDaoTestCase {
     assertThat(isRecent(semaphore.updatedAt, 60)).isTrue();
     assertThat(isRecent(semaphore.lockedAt, 60)).isTrue();
 
-    dao.unlock("foo");
+    dao.release("foo");
     assertThat(selectSemaphore("foo")).isNull();
   }
 
@@ -55,7 +55,7 @@ public class SemaphoreDaoTest extends AbstractDaoTestCase {
   public void fail_to_acquire_locked_semaphore() throws Exception {
     setupData("old_semaphore");
     SemaphoreDao dao = new SemaphoreDao(getMyBatis());
-    assertThat(dao.lock("foo", Integer.MAX_VALUE)).isFalse();
+    assertThat(dao.acquire("foo", Integer.MAX_VALUE)).isFalse();
 
     Semaphore semaphore = selectSemaphore("foo");
     assertThat(semaphore).isNotNull();
@@ -69,7 +69,7 @@ public class SemaphoreDaoTest extends AbstractDaoTestCase {
   public void acquire_long_locked_semaphore() throws Exception {
     setupData("old_semaphore");
     SemaphoreDao dao = new SemaphoreDao(getMyBatis());
-    assertThat(dao.lock("foo", 60)).isTrue();
+    assertThat(dao.acquire("foo", 60)).isTrue();
 
     Semaphore semaphore = selectSemaphore("foo");
     assertThat(semaphore).isNotNull();
@@ -83,8 +83,8 @@ public class SemaphoreDaoTest extends AbstractDaoTestCase {
   public void test_concurrent_locks() throws Exception {
     SemaphoreDao dao = new SemaphoreDao(getMyBatis());
 
-    for (int tests = 0; tests < 5000; tests++) {
-      dao.unlock("my-lock");
+    for (int tests = 0; tests < 5; tests++) {
+      dao.release("my-lock");
       int size = 5;
       CyclicBarrier barrier = new CyclicBarrier(size);
       CountDownLatch latch = new CountDownLatch(size);
@@ -152,7 +152,7 @@ public class SemaphoreDaoTest extends AbstractDaoTestCase {
       try {
         barrier.await();
         for (int i = 0; i < 100; i++) {
-          if (dao.lock("my-lock", 60 * 5)) {
+          if (dao.acquire("my-lock", 60 * 5)) {
             locks.incrementAndGet();
           }
         }
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
new file mode 100644 (file)
index 0000000..f01a6e6
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * 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.api.utils;
+
+import org.sonar.api.BatchComponent;
+import org.sonar.api.ServerComponent;
+
+/**
+ * A semaphore shared among all the processes that can connect to the central database.
+ *
+ * @since 3.4
+ */
+public interface DatabaseSemaphore extends BatchComponent, ServerComponent {
+
+  boolean acquire(String name, int maxDurationInSeconds);
+
+  void release(String name);
+
+}