]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-5183 timezones - semaphores migration 78/head
authorTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Thu, 5 Feb 2015 15:47:06 +0000 (16:47 +0100)
committerTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Tue, 10 Feb 2015 17:03:03 +0000 (18:03 +0100)
17 files changed:
server/sonar-server/src/main/java/org/sonar/server/db/migrations/DatabaseMigrations.java
server/sonar-server/src/main/java/org/sonar/server/db/migrations/v51/FeedSemaphoresLongDates.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/db/migrations/v51/FeedSemaphoresLongDatesTest.java [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v51/FeedSemaphoresLongDatesTest/before.xml [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v51/FeedSemaphoresLongDatesTest/schema.sql [new file with mode: 0644]
server/sonar-web/src/main/webapp/WEB-INF/db/migrate/784_add_semaphores_long_dates.rb [new file with mode: 0644]
server/sonar-web/src/main/webapp/WEB-INF/db/migrate/785_feed_semaphores_long_dates.rb [new file with mode: 0644]
server/sonar-web/src/main/webapp/WEB-INF/db/migrate/786_rename_semaphores_long_dates.rb [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/persistence/DatabaseVersion.java
sonar-core/src/main/java/org/sonar/core/persistence/SemaphoreDao.java
sonar-core/src/main/java/org/sonar/core/persistence/SemaphoreDto.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/main/resources/org/sonar/core/persistence/rows-h2.sql
sonar-core/src/main/resources/org/sonar/core/persistence/schema-h2.ddl
sonar-core/src/test/java/org/sonar/core/persistence/SemaphoreDaoTest.java
sonar-core/src/test/resources/org/sonar/core/persistence/SemaphoreDaoTest/old_semaphore.xml

index 43d9dfbdb9c016fa5d62e89d3d1c4bd099624495..813d7623906561b0607d592c4f2b9f2f0bf4207e 100644 (file)
@@ -87,6 +87,7 @@ public interface DatabaseMigrations {
     FeedIssueComponentUuids.class,
     FeedSnapshotsLongDates.class,
     FeedIssuesLongDates.class,
-    FeedFileSourcesBinaryData.class
+    FeedFileSourcesBinaryData.class,
+    FeedSemaphoresLongDates.class
     );
 }
diff --git a/server/sonar-server/src/main/java/org/sonar/server/db/migrations/v51/FeedSemaphoresLongDates.java b/server/sonar-server/src/main/java/org/sonar/server/db/migrations/v51/FeedSemaphoresLongDates.java
new file mode 100644 (file)
index 0000000..1ddc3a0
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.sonar.server.db.migrations.v51;
+
+import org.sonar.api.utils.System2;
+import org.sonar.core.persistence.Database;
+import org.sonar.server.db.migrations.BaseDataChange;
+import org.sonar.server.db.migrations.MassUpdate;
+import org.sonar.server.db.migrations.Select;
+import org.sonar.server.db.migrations.SqlStatement;
+
+import java.sql.SQLException;
+import java.util.Date;
+
+public class FeedSemaphoresLongDates extends BaseDataChange {
+
+  private final System2 system2;
+
+  public FeedSemaphoresLongDates(Database db, System2 system2) {
+    super(db);
+    this.system2 = system2;
+  }
+
+  @Override
+  public void execute(Context context) throws SQLException {
+    final long now = system2.now();
+    MassUpdate massUpdate = context.prepareMassUpdate();
+    massUpdate
+      .select("SELECT s.created_at, s.updated_at, s.locked_at, s.id FROM semaphores s WHERE created_at_ms IS NULL");
+    massUpdate
+      .update("UPDATE semaphores SET created_at_ms=?, updated_at_ms=?, locked_at_ms=? WHERE id=?");
+    massUpdate.rowPluralName("semaphores");
+    massUpdate.execute(new MassUpdate.Handler() {
+      @Override
+      public boolean handle(Select.Row row, SqlStatement update) throws SQLException {
+        for (int i = 1; i <= 3; i++) {
+          Date date = row.getDate(i);
+          update.setLong(i, date == null ? null : Math.min(now, date.getTime()));
+        }
+
+        Long id = row.getLong(4);
+        update.setLong(4, id);
+
+        return true;
+      }
+    });
+  }
+
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/db/migrations/v51/FeedSemaphoresLongDatesTest.java b/server/sonar-server/src/test/java/org/sonar/server/db/migrations/v51/FeedSemaphoresLongDatesTest.java
new file mode 100644 (file)
index 0000000..21f9026
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.sonar.server.db.migrations.v51;
+
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.sonar.api.utils.System2;
+import org.sonar.core.persistence.DbTester;
+import org.sonar.server.db.migrations.DatabaseMigration;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.sonar.api.utils.DateUtils.parseDate;
+
+public class FeedSemaphoresLongDatesTest {
+  @ClassRule
+  public static DbTester db = new DbTester().schema(FeedSemaphoresLongDatesTest.class, "schema.sql");
+
+  @Before
+  public void before() throws Exception {
+    db.prepareDbUnit(getClass(), "before.xml");
+  }
+
+  @Test
+  public void execute() throws Exception {
+    DatabaseMigration migration = newMigration(System2.INSTANCE);
+
+    migration.execute();
+
+    int count = db
+      .countSql("select count(*) from semaphores where " +
+        "created_at_ms is not null " +
+        "and updated_at_ms is not null " +
+        "and locked_at_ms is not null");
+    assertThat(count).isEqualTo(2);
+  }
+
+  @Test
+  public void take_now_if_date_in_the_future() throws Exception {
+    System2 system = mock(System2.class);
+    when(system.now()).thenReturn(1234L);
+
+    DatabaseMigration migration = newMigration(system);
+
+    migration.execute();
+
+    int count = db
+      .countSql("select count(*) from semaphores where " +
+        "created_at_ms = 1234");
+    assertThat(count).isEqualTo(1);
+  }
+
+  @Test
+  public void take_snapshot_date_if_in_the_past() throws Exception {
+    DatabaseMigration migration = newMigration(System2.INSTANCE);
+
+    migration.execute();
+
+    long snapshotTime = parseDate("2014-09-25").getTime();
+    int count = db
+      .countSql("select count(*) from semaphores where " +
+        "created_at_ms=" + snapshotTime);
+    assertThat(count).isEqualTo(1);
+  }
+
+  private FeedSemaphoresLongDates newMigration(System2 system) {
+    return new FeedSemaphoresLongDates(db.database(), system);
+  }
+}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v51/FeedSemaphoresLongDatesTest/before.xml b/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v51/FeedSemaphoresLongDatesTest/before.xml
new file mode 100644 (file)
index 0000000..1dc6228
--- /dev/null
@@ -0,0 +1,34 @@
+<dataset>
+  <!-- new migration -->
+  <semaphores
+      id="1"
+      created_at="2014-09-25"
+      created_at_ms="[null]"
+      updated_at="2014-09-25"
+      updated_at_ms="[null]"
+      locked_at="2014-09-25"
+      locked_at_ms="[null]"
+      />
+
+  <!-- re-entrant migration - ignore the ones that are already fed with new dates -->
+  <semaphores
+      id="2"
+      created_at="2014-09-25"
+      created_at_ms="1500000000"
+      updated_at="2014-09-25"
+      updated_at_ms="1500000000"
+      locked_at="2014-09-25"
+      locked_at_ms="1500000000"
+      />
+
+  <!-- NULL dates -->
+  <semaphores
+      id="3"
+      created_at="[null]"
+      created_at_ms="[null]"
+      updated_at="[null]"
+      updated_at_ms="[null]"
+      locked_at="[null]"
+      locked_at_ms="[null]"
+      />
+</dataset>
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v51/FeedSemaphoresLongDatesTest/schema.sql b/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v51/FeedSemaphoresLongDatesTest/schema.sql
new file mode 100644 (file)
index 0000000..6d652a8
--- /dev/null
@@ -0,0 +1,9 @@
+CREATE TABLE "SEMAPHORES" (
+  "ID" BIGINT NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
+  "CREATED_AT" TIMESTAMP,
+  "CREATED_AT_MS" BIGINT,
+  "LOCKED_AT" TIMESTAMP,
+  "LOCKED_AT_MS" BIGINT,
+  "UPDATED_AT" TIMESTAMP,
+  "UPDATED_AT_MS" BIGINT,
+);
diff --git a/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/784_add_semaphores_long_dates.rb b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/784_add_semaphores_long_dates.rb
new file mode 100644 (file)
index 0000000..b555bf7
--- /dev/null
@@ -0,0 +1,30 @@
+#
+# SonarQube, open source software quality management tool.
+# Copyright (C) 2008-2014 SonarSource
+# mailto:contact AT sonarsource DOT com
+#
+# SonarQube 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.
+#
+# SonarQube 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 this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#
+
+#
+# SonarQube 5.1
+#
+class AddSemaphoresLongDates < ActiveRecord::Migration
+  def self.up
+    add_column 'semaphores', :created_at_ms, :big_integer, :null => true
+    add_column 'semaphores', :updated_at_ms, :big_integer, :null => true
+    add_column 'semaphores', :locked_at_ms, :big_integer, :null => true
+  end
+end
diff --git a/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/785_feed_semaphores_long_dates.rb b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/785_feed_semaphores_long_dates.rb
new file mode 100644 (file)
index 0000000..7936cbe
--- /dev/null
@@ -0,0 +1,29 @@
+#
+# SonarQube, open source software quality management tool.
+# Copyright (C) 2008-2014 SonarSource
+# mailto:contact AT sonarsource DOT com
+#
+# SonarQube 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.
+#
+# SonarQube 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 this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#
+
+#
+# SonarQube 5.1
+#
+class FeedSemaphoresLongDates < ActiveRecord::Migration
+  def self.up
+    execute_java_migration('org.sonar.server.db.migrations.v51.FeedSemaphoresLongDates')
+  end
+end
+
diff --git a/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/786_rename_semaphores_long_dates.rb b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/786_rename_semaphores_long_dates.rb
new file mode 100644 (file)
index 0000000..62f4e72
--- /dev/null
@@ -0,0 +1,34 @@
+#
+# SonarQube, open source software quality management tool.
+# Copyright (C) 2008-2014 SonarSource
+# mailto:contact AT sonarsource DOT com
+#
+# SonarQube 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.
+#
+# SonarQube 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 this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#
+
+#
+# SonarQube 5.1
+#
+class RenameSemaphoresLongDates < ActiveRecord::Migration
+  def self.up
+    remove_column 'semaphores', 'created_at'
+    remove_column 'semaphores', 'updated_at'
+    remove_column 'semaphores', 'locked_at'
+    rename_column 'semaphores', 'created_at_ms', 'created_at'
+    rename_column 'semaphores', 'updated_at_ms', 'updated_at'
+    rename_column 'semaphores', 'locked_at_ms', 'locked_at'
+  end
+end
+
index 80de635be56a5bcfb30ade25fa0ae2766d2893b9..371f1e964fcb4857334f5c059f95be7a4bbcdd14 100644 (file)
@@ -33,7 +33,7 @@ import java.util.List;
  */
 public class DatabaseVersion implements BatchComponent, ServerComponent {
 
-  public static final int LAST_VERSION = 783;
+  public static final int LAST_VERSION = 786;
 
   /**
    * List of all the tables.n
index 00fbcad50129b799bb79ab550ef39003b698f45a..e50e39c3fa8eba644c1cd71327bfeedce1bda0e2 100644 (file)
  */
 package org.sonar.core.persistence;
 
-import com.google.common.base.Preconditions;
 import com.google.common.base.Strings;
-import org.apache.commons.lang.time.DateUtils;
 import org.apache.ibatis.session.SqlSession;
 import org.sonar.api.utils.Semaphores;
+import org.sonar.api.utils.System2;
 
 import javax.annotation.CheckForNull;
-import java.util.Date;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static org.sonar.api.utils.DateUtils.longToDate;
 
 /**
  * @since 3.4
@@ -35,80 +36,66 @@ public class SemaphoreDao {
 
   private static final String SEMAPHORE_NAME_MUST_NOT_BE_EMPTY = "Semaphore name must not be empty";
   private final MyBatis mybatis;
+  private final System2 system;
 
-  public SemaphoreDao(MyBatis mybatis) {
+  public SemaphoreDao(MyBatis mybatis, System2 system) {
     this.mybatis = mybatis;
+    this.system = system;
   }
 
   public Semaphores.Semaphore acquire(String name, int maxAgeInSeconds) {
-    Preconditions.checkArgument(!Strings.isNullOrEmpty(name), SEMAPHORE_NAME_MUST_NOT_BE_EMPTY);
-    Preconditions.checkArgument(maxAgeInSeconds >= 0, "Semaphore max age must be positive: " + maxAgeInSeconds);
+    checkArgument(!Strings.isNullOrEmpty(name), SEMAPHORE_NAME_MUST_NOT_BE_EMPTY);
+    checkArgument(maxAgeInSeconds >= 0, "Semaphore max age must be positive: " + maxAgeInSeconds);
 
-    SqlSession session = mybatis.openSession(false);
-    try {
-      SemaphoreMapper mapper = session.getMapper(SemaphoreMapper.class);
-      Date dbNow = mapper.now();
-      SemaphoreDto semaphore = tryToInsert(name, dbNow, session);
+    try (SqlSession session = mybatis.openSession(false)) {
+      SemaphoreDto semaphore = tryToInsert(name, system.now(), session);
       boolean isAcquired;
       if (semaphore == null) {
         semaphore = selectSemaphore(name, session);
-        isAcquired = acquireIfOutdated(name, maxAgeInSeconds, session, mapper);
+        isAcquired = acquireIfOutdated(name, maxAgeInSeconds, session);
       } else {
         isAcquired = true;
       }
-      return createLock(semaphore, session, isAcquired);
-    } finally {
-      MyBatis.closeQuietly(session);
+      return createLock(semaphore, isAcquired);
     }
   }
 
   public Semaphores.Semaphore acquire(String name) {
-    Preconditions.checkArgument(!Strings.isNullOrEmpty(name), SEMAPHORE_NAME_MUST_NOT_BE_EMPTY);
+    checkArgument(!Strings.isNullOrEmpty(name), SEMAPHORE_NAME_MUST_NOT_BE_EMPTY);
 
-    SqlSession session = mybatis.openSession(false);
-    try {
-      SemaphoreMapper mapper = session.getMapper(SemaphoreMapper.class);
-      Date now = mapper.now();
-      SemaphoreDto semaphore = tryToInsert(name, now, session);
+    try (SqlSession session = mybatis.openSession(false)) {
+      SemaphoreDto semaphore = tryToInsert(name, system.now(), session);
       if (semaphore == null) {
         semaphore = selectSemaphore(name, session);
-        return createLock(semaphore, session, false);
+        return createLock(semaphore, false);
       } else {
-        return createLock(semaphore, session, true);
+        return createLock(semaphore, true);
       }
-    } finally {
-      MyBatis.closeQuietly(session);
     }
   }
 
   public void update(Semaphores.Semaphore semaphore) {
-    Preconditions.checkArgument(semaphore != null, "Semaphore must not be null");
+    checkArgument(semaphore != null, "Semaphore must not be null");
 
-    SqlSession session = mybatis.openSession(false);
-    try {
-      SemaphoreMapper mapper = session.getMapper(SemaphoreMapper.class);
-      mapper.update(semaphore.getName());
+    try (SqlSession session = mybatis.openSession(false)) {
+      mapper(session).update(semaphore.getName(), system.now());
       session.commit();
-    } finally {
-      MyBatis.closeQuietly(session);
     }
   }
 
   public void release(String name) {
-    Preconditions.checkArgument(!Strings.isNullOrEmpty(name), SEMAPHORE_NAME_MUST_NOT_BE_EMPTY);
-    SqlSession session = mybatis.openSession(false);
-    try {
-      session.getMapper(SemaphoreMapper.class).release(name);
+    checkArgument(!Strings.isNullOrEmpty(name), SEMAPHORE_NAME_MUST_NOT_BE_EMPTY);
+    try (SqlSession session = mybatis.openSession(false)) {
+      mapper(session).release(name);
       session.commit();
-    } finally {
-      MyBatis.closeQuietly(session);
     }
   }
 
-  private boolean acquireIfOutdated(String name, int maxAgeInSeconds, SqlSession session, SemaphoreMapper mapper) {
-    Date dbNow = mapper.now();
-    Date updatedBefore = DateUtils.addSeconds(dbNow, -maxAgeInSeconds);
-    boolean ok = mapper.acquire(name, updatedBefore) == 1;
+  private boolean acquireIfOutdated(String name, int maxAgeInSeconds, SqlSession session) {
+    long now = system.now();
+    long updatedBefore = now - (long) maxAgeInSeconds * 1000;
+
+    boolean ok = mapper(session).acquire(name, updatedBefore, now) == 1;
     session.commit();
     return ok;
   }
@@ -118,50 +105,46 @@ public class SemaphoreDao {
    * the lock date)
    */
   @CheckForNull
-  private SemaphoreDto tryToInsert(String name, Date lockedNow, SqlSession session) {
+  private SemaphoreDto tryToInsert(String name, long lockedNow, SqlSession session) {
     try {
-      SemaphoreMapper mapper = session.getMapper(SemaphoreMapper.class);
+      long now = system.now();
       SemaphoreDto semaphore = new SemaphoreDto()
-          .setName(name)
-          .setLockedAt(lockedNow);
-      mapper.initialize(semaphore);
+        .setName(name)
+        .setCreatedAt(now)
+        .setUpdatedAt(now)
+        .setLockedAt(lockedNow);
+      mapper(session).initialize(semaphore);
       session.commit();
       return semaphore;
     } catch (Exception e) {
-      // probably because of the semaphore already exists in db
+      // probably because the semaphore already exists in db
       session.rollback();
       return null;
     }
   }
 
-  private Semaphores.Semaphore createLock(SemaphoreDto dto, SqlSession session, boolean acquired) {
+  private Semaphores.Semaphore createLock(SemaphoreDto dto, boolean acquired) {
     Semaphores.Semaphore semaphore = new Semaphores.Semaphore()
-        .setName(dto.getName())
-        .setLocked(acquired)
-        .setLockedAt(dto.getLockedAt())
-        .setCreatedAt(dto.getCreatedAt())
-        .setUpdatedAt(dto.getUpdatedAt());
+      .setName(dto.getName())
+      .setLocked(acquired)
+      .setLockedAt(longToDate(dto.getLockedAt()))
+      .setCreatedAt(longToDate(dto.getCreatedAt()))
+      .setUpdatedAt(longToDate(dto.getUpdatedAt()));
     if (!acquired) {
-      semaphore.setDurationSinceLocked(getDurationSinceLocked(dto, session));
+      semaphore.setDurationSinceLocked(lockedSince(dto));
     }
     return semaphore;
   }
 
-  private long getDurationSinceLocked(SemaphoreDto semaphore, SqlSession session) {
-    long now = now(session).getTime();
-    semaphore.getLockedAt();
-    long lockedAt = semaphore.getLockedAt().getTime();
-    return now - lockedAt;
+  private long lockedSince(SemaphoreDto semaphore) {
+    return system.now() - semaphore.getLockedAt();
   }
 
   protected SemaphoreDto selectSemaphore(String name, SqlSession session) {
-    SemaphoreMapper mapper = session.getMapper(SemaphoreMapper.class);
-    return mapper.selectSemaphore(name);
+    return mapper(session).selectSemaphore(name);
   }
 
-  protected Date now(SqlSession session) {
-    SemaphoreMapper mapper = session.getMapper(SemaphoreMapper.class);
-    return mapper.now();
+  private SemaphoreMapper mapper(SqlSession session) {
+    return session.getMapper(SemaphoreMapper.class);
   }
-
 }
index b556030aa0aba88b613ae824e691b5b15c45b11d..d28bb804ab6c1aaf5c0d272c747d7fdfa3b51197 100644 (file)
@@ -22,8 +22,6 @@ package org.sonar.core.persistence;
 import org.apache.commons.codec.digest.DigestUtils;
 import org.apache.commons.lang.builder.ReflectionToStringBuilder;
 
-import java.util.Date;
-
 /**
  * @since 3.4
  */
@@ -31,9 +29,9 @@ public class SemaphoreDto {
   private Long id;
   private String name;
   private String checksum;
-  private Date lockedAt;
-  private Date createdAt;
-  private Date updatedAt;
+  private Long lockedAt;
+  private Long createdAt;
+  private Long updatedAt;
 
   public String getName() {
     return name;
@@ -45,11 +43,11 @@ public class SemaphoreDto {
     return this;
   }
 
-  public Date getLockedAt() {
+  public Long getLockedAt() {
     return lockedAt;
   }
 
-  public SemaphoreDto setLockedAt(Date d) {
+  public SemaphoreDto setLockedAt(Long d) {
     this.lockedAt = d;
     return this;
   }
@@ -63,20 +61,20 @@ public class SemaphoreDto {
     return this;
   }
 
-  public Date getCreatedAt() {
+  public Long getCreatedAt() {
     return createdAt;
   }
 
-  public SemaphoreDto setCreatedAt(Date createdAt) {
+  public SemaphoreDto setCreatedAt(Long createdAt) {
     this.createdAt = createdAt;
     return this;
   }
 
-  public Date getUpdatedAt() {
+  public Long getUpdatedAt() {
     return updatedAt;
   }
 
-  public SemaphoreDto setUpdatedAt(Date updatedAt) {
+  public SemaphoreDto setUpdatedAt(Long updatedAt) {
     this.updatedAt = updatedAt;
     return this;
   }
index 489243cd931df7ca77611ade30f2e651ce6b6a09..22773833bbc944fc5e6e763a6e239da70fd46cb5 100644 (file)
@@ -21,19 +21,15 @@ package org.sonar.core.persistence;
 
 import org.apache.ibatis.annotations.Param;
 
-import java.util.Date;
-
 public interface SemaphoreMapper {
 
   int initialize(SemaphoreDto semaphore);
 
-  int acquire(@Param("name") String name, @Param("updatedBefore") Date updatedBefore);
-
-  Date now();
+  int acquire(@Param("name") String name, @Param("updatedBefore") Long updatedBefore, @Param("now") Long now);
 
   void release(String name);
 
   SemaphoreDto selectSemaphore(@Param("name") String name);
 
-  void update(String name);
+  void update(@Param("name") String name, @Param("now") Long now);
 }
index bdd0d86a85d2fb87d1e794e23675f27fd608147f..4c42b26ea17fdb08cf7d58de45e7061ba15dae29 100644 (file)
@@ -5,20 +5,12 @@
 
   <insert id="initialize" parameterType="map" useGeneratedKeys="false" >
     INSERT INTO semaphores (name, checksum, created_at, updated_at, locked_at)
-    VALUES (#{name}, #{checksum}, current_timestamp, current_timestamp, #{lockedAt})
+    VALUES (#{name}, #{checksum}, #{createdAt}, #{updatedAt}, #{lockedAt})
   </insert>
 
-  <select id="now" resultType="Date" >
-    select current_timestamp
-  </select>
-
-  <select id="now" databaseId="oracle" resultType="Date" >
-    select current_timestamp from dual
-  </select>
-
   <update id="acquire" parameterType="map">
     update semaphores
-    set updated_at = current_timestamp, locked_at = current_timestamp
+    set updated_at = #{now}, locked_at = #{now}
     where name=#{name}
     <if test="updatedBefore != null">
       AND updated_at &lt; #{updatedBefore}
@@ -34,9 +26,9 @@
     from semaphores s where s.name=#{name}
   </select>
 
-  <update id="update" parameterType="String" >
+  <update id="update" parameterType="map" >
     update semaphores
-    set updated_at = current_timestamp
+    set updated_at = #{now}
     where name=#{name}
   </update>
 
index fd2663d75e5969be160d3b7a3e2dd6e52f2ad6d5..60192f301dfc10f009696ffc492f5033d0adf871 100644 (file)
@@ -311,6 +311,9 @@ INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('780');
 INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('781');
 INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('782');
 INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('783');
+INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('784');
+INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('785');
+INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('786');
 
 INSERT INTO USERS(ID, LOGIN, NAME, EMAIL, CRYPTED_PASSWORD, SALT, CREATED_AT, UPDATED_AT, REMEMBER_TOKEN, REMEMBER_TOKEN_EXPIRES_AT) VALUES (1, 'admin', 'Administrator', '', 'a373a0e667abb2604c1fd571eb4ad47fe8cc0878', '48bc4b0d93179b5103fd3885ea9119498e9d161b', '1418215735482', '1418215735482', null, null);
 ALTER TABLE USERS ALTER COLUMN ID RESTART WITH 2;
index fadf4581aa951368070d2524bc1e7be8a5351e38..81d7d1d1779aca6b4b2e4361089f66cc8db0f3d6 100644 (file)
@@ -403,9 +403,9 @@ CREATE TABLE "SEMAPHORES" (
   "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
   "NAME" VARCHAR(4000),
   "CHECKSUM" VARCHAR(200),
-  "CREATED_AT" TIMESTAMP,
-  "UPDATED_AT" TIMESTAMP,
-  "LOCKED_AT" TIMESTAMP
+  "CREATED_AT" BIGINT,
+  "UPDATED_AT" BIGINT,
+  "LOCKED_AT" BIGINT
 );
 
 CREATE TABLE "MEASURE_FILTERS" (
index a2652f1aaa1ab844c79b87b113114b4c3b3a2a33..5710a80c2a708f9034a890230c5f04de5a8b52e3 100644 (file)
  */
 package org.sonar.core.persistence;
 
-import org.apache.commons.lang.time.DateUtils;
 import org.apache.ibatis.session.SqlSession;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
 import org.sonar.api.utils.Semaphores;
+import org.sonar.api.utils.System2;
 
-import java.util.Date;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.CyclicBarrier;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -37,10 +36,12 @@ import static org.assertj.core.api.Assertions.assertThat;
 public class SemaphoreDaoTest extends AbstractDaoTestCase {
 
   private SemaphoreDao dao;
+  private System2 system;
 
   @Before
   public void before() {
-    dao = new SemaphoreDao(getMyBatis());
+    system = System2.INSTANCE;
+    dao = new SemaphoreDao(getMyBatis(), system);
   }
 
   @Rule
@@ -51,7 +52,7 @@ public class SemaphoreDaoTest extends AbstractDaoTestCase {
     thrown.expect(IllegalArgumentException.class);
     thrown.expectMessage("Semaphore name must not be empty");
 
-    SemaphoreDao dao = new SemaphoreDao(getMyBatis());
+    SemaphoreDao dao = new SemaphoreDao(getMyBatis(), system);
     dao.acquire(null, 5000);
   }
 
@@ -60,7 +61,7 @@ public class SemaphoreDaoTest extends AbstractDaoTestCase {
     thrown.expect(IllegalArgumentException.class);
     thrown.expectMessage("Semaphore max age must be positive: -5000");
 
-    SemaphoreDao dao = new SemaphoreDao(getMyBatis());
+    SemaphoreDao dao = new SemaphoreDao(getMyBatis(), system);
     dao.acquire("foo", -5000);
   }
 
@@ -69,7 +70,7 @@ public class SemaphoreDaoTest extends AbstractDaoTestCase {
     thrown.expect(IllegalArgumentException.class);
     thrown.expectMessage("Semaphore name must not be empty");
 
-    SemaphoreDao dao = new SemaphoreDao(getMyBatis());
+    SemaphoreDao dao = new SemaphoreDao(getMyBatis(), system);
     dao.release(null);
   }
 
@@ -97,14 +98,14 @@ public class SemaphoreDaoTest extends AbstractDaoTestCase {
     assertThat(lock.getDurationSinceLocked()).isNull();
 
     SemaphoreDto semaphore = selectSemaphore("foo");
-    assertThat(semaphore.getCreatedAt().getTime()).isEqualTo(semaphore.getUpdatedAt().getTime());
+    assertThat(semaphore.getCreatedAt()).isEqualTo(semaphore.getUpdatedAt());
 
     Thread.sleep(1000);
 
     dao.update(lock);
 
     semaphore = selectSemaphore("foo");
-    assertThat(semaphore.getCreatedAt().getTime()).isLessThan(semaphore.getUpdatedAt().getTime());
+    assertThat(semaphore.getCreatedAt()).isLessThan(semaphore.getUpdatedAt());
 
     dao.release("foo");
     assertThat(selectSemaphore("foo")).isNull();
@@ -247,19 +248,11 @@ public class SemaphoreDaoTest extends AbstractDaoTestCase {
     }
   }
 
-  private boolean isRecent(Date date) {
-    Date future = DateUtils.addMinutes(now(), 1);
-    Date past = DateUtils.addDays(now(), -1);
-    return date.after(past) && date.before(future);
-  }
-
-  private Date now() {
-    SqlSession session = getMyBatis().openSession();
-    try {
-      return dao.now(session);
-    } finally {
-      MyBatis.closeQuietly(session);
-    }
+  private boolean isRecent(Long date) {
+    int oneMinuteInMs = 60 * 1000;
+    long future = system.now() + oneMinuteInMs;
+    long past = system.now() - oneMinuteInMs;
+    return date > past && date < future;
   }
 
   private static class Runner extends Thread {
index 903ea7916c7b9f1b86b1919a786f3f9af236786e..23a1d4ff67bc7fe1f02a5e03502316bd3e91d93f 100644 (file)
@@ -1,3 +1,3 @@
 <dataset>
-  <semaphores id="1" name="foo" checksum="acbd18db4cc2f85cedef654fccc4a4d8" created_at="2010-01-25" updated_at="2010-01-25" locked_at="2010-01-25"/>
-</dataset>
\ No newline at end of file
+  <semaphores id="1" name="foo" checksum="acbd18db4cc2f85cedef654fccc4a4d8" created_at="1264374000000" updated_at="1264374000000" locked_at="1264374000000"/>
+</dataset>