Selaa lähdekoodia

Implement and test DBStore swap_table functionality

Winston Li 10 vuotta sitten
vanhempi
sitoutus
9d19cdd261
14 muutettua tiedostoa jossa 252 lisäystä ja 47 poistoa
  1. 6 2
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/db/sqlite/SQLUpdate.java
  2. 9 7
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/db/sqlite/SqliteDBStore.java
  3. 30 0
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/db/sqlite/query/GetOldestProjectName.java
  4. 0 6
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/db/sqlite/query/GetProjectNamesSQLQuery.java
  5. 2 9
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/db/sqlite/update/create/CreateIndexURLIndexStore.java
  6. 0 8
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/db/sqlite/update/create/CreateProjectsTableSQLUpdate.java
  7. 27 0
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/db/sqlite/update/create/CreateSwapTable.java
  8. 19 0
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/db/sqlite/update/create/CreateSwapTableIndex.java
  9. 5 9
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/db/sqlite/update/create/CreateURLIndexStoreSQLUpdate.java
  10. 8 3
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/db/sqlite/update/delete/DeleteFilesForProjectSQLUpdate.java
  11. 9 2
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/db/sqlite/update/insert/AddURLIndexSQLUpdate.java
  12. 47 0
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/db/sqlite/update/insert/SetProjectLastAccessedTime.java
  13. 2 1
      services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/db/sqlite/update/insert/SetProjectSQLUpdate.java
  14. 88 0
      services/git-bridge/src/test/java/uk/ac/ic/wlgitbridge/bridge/db/sqlite/SqliteDBStoreTest.java

+ 6 - 2
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/db/sqlite/SQLUpdate.java

@@ -8,7 +8,11 @@ import java.sql.SQLException;
  */
 public interface SQLUpdate {
 
-    public String getSQL();
-    public void addParametersToStatement(PreparedStatement statement) throws SQLException;
+    String getSQL();
+    default void addParametersToStatement(
+            PreparedStatement statement
+    ) throws SQLException {
+
+    }
 
 }

+ 9 - 7
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/db/sqlite/SqliteDBStore.java

@@ -3,14 +3,14 @@ package uk.ac.ic.wlgitbridge.bridge.db.sqlite;
 import uk.ac.ic.wlgitbridge.bridge.db.DBInitException;
 import uk.ac.ic.wlgitbridge.bridge.db.DBStore;
 import uk.ac.ic.wlgitbridge.bridge.db.sqlite.query.GetLatestVersionForProjectSQLQuery;
+import uk.ac.ic.wlgitbridge.bridge.db.sqlite.query.GetOldestProjectName;
 import uk.ac.ic.wlgitbridge.bridge.db.sqlite.query.GetPathForURLInProjectSQLQuery;
 import uk.ac.ic.wlgitbridge.bridge.db.sqlite.query.GetProjectNamesSQLQuery;
-import uk.ac.ic.wlgitbridge.bridge.db.sqlite.update.create.CreateIndexURLIndexStore;
-import uk.ac.ic.wlgitbridge.bridge.db.sqlite.update.create.CreateProjectsTableSQLUpdate;
-import uk.ac.ic.wlgitbridge.bridge.db.sqlite.update.create.CreateURLIndexStoreSQLUpdate;
+import uk.ac.ic.wlgitbridge.bridge.db.sqlite.update.create.*;
 import uk.ac.ic.wlgitbridge.bridge.db.sqlite.update.delete.DeleteFilesForProjectSQLUpdate;
 import uk.ac.ic.wlgitbridge.bridge.db.sqlite.update.insert.AddURLIndexSQLUpdate;
 import uk.ac.ic.wlgitbridge.bridge.db.sqlite.update.insert.SetProjectSQLUpdate;
+import uk.ac.ic.wlgitbridge.bridge.db.sqlite.update.insert.SetProjectLastAccessedTime;
 
 import java.io.File;
 import java.sql.*;
@@ -80,15 +80,15 @@ public class SqliteDBStore implements DBStore {
 
     @Override
     public String getOldestUnswappedProject() {
-        throw new UnsupportedOperationException();
+        return query(new GetOldestProjectName());
     }
 
     @Override
     public void setLastAccessedTime(
             String projectName,
-            Timestamp time
+            Timestamp lastAccessed
     ) {
-        throw new UnsupportedOperationException();
+        update(new SetProjectLastAccessedTime(projectName, lastAccessed));
     }
 
     private Connection openConnectionTo(File dbFile) {
@@ -117,7 +117,9 @@ public class SqliteDBStore implements DBStore {
         Stream.of(
                 new CreateProjectsTableSQLUpdate(),
                 new CreateURLIndexStoreSQLUpdate(),
-                new CreateIndexURLIndexStore()
+                new CreateIndexURLIndexStore(),
+                new CreateSwapTable(),
+                new CreateSwapTableIndex()
         ).forEach(this::update);
     }
 

+ 30 - 0
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/db/sqlite/query/GetOldestProjectName.java

@@ -0,0 +1,30 @@
+package uk.ac.ic.wlgitbridge.bridge.db.sqlite.query;
+
+import uk.ac.ic.wlgitbridge.bridge.db.sqlite.SQLQuery;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+/**
+ * Created by winston on 23/08/2016.
+ */
+public class GetOldestProjectName implements SQLQuery<String> {
+
+    private static final String GET_OLDEST_PROJECT_NAME =
+            "SELECT `project_name`, MIN(`last_accessed`)\n" +
+            "    FROM `swap_table`";
+
+    @Override
+    public String getSQL() {
+        return GET_OLDEST_PROJECT_NAME;
+    }
+
+    @Override
+    public String processResultSet(ResultSet resultSet) throws SQLException {
+        while (resultSet.next()) {
+            return resultSet.getString("project_name");
+        }
+        return null;
+    }
+
+}

+ 0 - 6
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/db/sqlite/query/GetProjectNamesSQLQuery.java

@@ -2,7 +2,6 @@ package uk.ac.ic.wlgitbridge.bridge.db.sqlite.query;
 
 import uk.ac.ic.wlgitbridge.bridge.db.sqlite.SQLQuery;
 
-import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.util.LinkedList;
@@ -30,9 +29,4 @@ public class GetProjectNamesSQLQuery implements SQLQuery<List<String>> {
         return GET_URL_INDEXES_FOR_PROJECT_NAME;
     }
 
-    @Override
-    public void addParametersToStatement(PreparedStatement statement) throws SQLException {
-
-    }
-
 }

+ 2 - 9
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/db/sqlite/update/create/CreateIndexURLIndexStore.java

@@ -2,25 +2,18 @@ package uk.ac.ic.wlgitbridge.bridge.db.sqlite.update.create;
 
 import uk.ac.ic.wlgitbridge.bridge.db.sqlite.SQLUpdate;
 
-import java.sql.PreparedStatement;
-import java.sql.SQLException;
-
 /**
  * Created by Winston on 21/02/15.
  */
 public class CreateIndexURLIndexStore implements SQLUpdate {
 
     public static final String CREATE_INDEX_URL_INDEX_STORE =
-            "CREATE UNIQUE INDEX IF NOT EXISTS `project_path_index` ON `url_index_store`(`project_name`, `path`);\n";
+            "CREATE UNIQUE INDEX IF NOT EXISTS `project_path_index` " +
+                    "ON `url_index_store`(`project_name`, `path`);\n";
 
     @Override
     public String getSQL() {
         return CREATE_INDEX_URL_INDEX_STORE;
     }
 
-    @Override
-    public void addParametersToStatement(PreparedStatement statement) throws SQLException {
-
-    }
-
 }

+ 0 - 8
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/db/sqlite/update/create/CreateProjectsTableSQLUpdate.java

@@ -2,9 +2,6 @@ package uk.ac.ic.wlgitbridge.bridge.db.sqlite.update.create;
 
 import uk.ac.ic.wlgitbridge.bridge.db.sqlite.SQLUpdate;
 
-import java.sql.PreparedStatement;
-import java.sql.SQLException;
-
 /**
  * Created by Winston on 20/11/14.
  */
@@ -21,9 +18,4 @@ public class CreateProjectsTableSQLUpdate implements SQLUpdate {
         return CREATE_PROJECTS_TABLE;
     }
 
-    @Override
-    public void addParametersToStatement(PreparedStatement statement) throws SQLException {
-
-    }
-
 }

+ 27 - 0
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/db/sqlite/update/create/CreateSwapTable.java

@@ -0,0 +1,27 @@
+package uk.ac.ic.wlgitbridge.bridge.db.sqlite.update.create;
+
+import uk.ac.ic.wlgitbridge.bridge.db.sqlite.SQLUpdate;
+
+/**
+ * Created by winston on 23/08/2016.
+ */
+public class CreateSwapTable implements SQLUpdate {
+
+    private static final String CREATE_SWAP_TABLE =
+            "CREATE TABLE IF NOT EXISTS `swap_table` (\n" +
+            "        `project_name` VARCHAR NOT NULL DEFAULT '',\n" +
+            "        `last_accessed` DATETIME NULL DEFAULT 0,\n" +
+            "        PRIMARY KEY (`project_name`),\n" +
+            "        CONSTRAINT `swap_table_fk_1`\n" +
+            "            FOREIGN KEY (`project_name`)\n" +
+            "            REFERENCES `projects`(`name`)\n" +
+            "            ON DELETE CASCADE\n" +
+            "            ON UPDATE CASCADE\n" +
+            ")";
+
+    @Override
+    public String getSQL() {
+        return CREATE_SWAP_TABLE;
+    }
+
+}

+ 19 - 0
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/db/sqlite/update/create/CreateSwapTableIndex.java

@@ -0,0 +1,19 @@
+package uk.ac.ic.wlgitbridge.bridge.db.sqlite.update.create;
+
+import uk.ac.ic.wlgitbridge.bridge.db.sqlite.SQLUpdate;
+
+/**
+ * Created by winston on 23/08/2016.
+ */
+public class CreateSwapTableIndex implements SQLUpdate {
+
+    private static final String CREATE_SWAP_TABLE_INDEX =
+            "CREATE INDEX IF NOT EXISTS `swap_table_index`\n" +
+            "    ON `swap_table`(`last_accessed`)";
+
+    @Override
+    public String getSQL() {
+        return CREATE_SWAP_TABLE_INDEX;
+    }
+
+}

+ 5 - 9
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/db/sqlite/update/create/CreateURLIndexStoreSQLUpdate.java

@@ -2,9 +2,6 @@ package uk.ac.ic.wlgitbridge.bridge.db.sqlite.update.create;
 
 import uk.ac.ic.wlgitbridge.bridge.db.sqlite.SQLUpdate;
 
-import java.sql.PreparedStatement;
-import java.sql.SQLException;
-
 /**
  * Created by Winston on 20/11/14.
  */
@@ -16,7 +13,11 @@ public class CreateURLIndexStoreSQLUpdate implements SQLUpdate {
             "  `url` text NOT NULL,\n"+
             "  `path` text NOT NULL,\n"+
             "  PRIMARY KEY (`project_name`,`url`),\n"+
-            "  CONSTRAINT `url_index_store_ibfk_1` FOREIGN KEY (`project_name`) REFERENCES `projects` (`name`) ON DELETE CASCADE ON UPDATE CASCADE\n"+
+            "  CONSTRAINT `url_index_store_ibfk_1` " +
+                    "FOREIGN KEY (`project_name`) " +
+                    "REFERENCES `projects` (`name`) " +
+                    "ON DELETE CASCADE " +
+                    "ON UPDATE CASCADE\n"+
             ");\n";
 
     @Override
@@ -24,9 +25,4 @@ public class CreateURLIndexStoreSQLUpdate implements SQLUpdate {
         return CREATE_URL_INDEX_STORE;
     }
 
-    @Override
-    public void addParametersToStatement(PreparedStatement statement) throws SQLException {
-
-    }
-
 }

+ 8 - 3
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/db/sqlite/update/delete/DeleteFilesForProjectSQLUpdate.java

@@ -11,7 +11,8 @@ import java.sql.SQLException;
 public class DeleteFilesForProjectSQLUpdate implements SQLUpdate {
 
     private static final String DELETE_URL_INDEXES_FOR_PROJECT_NAME =
-            "DELETE FROM `url_index_store` WHERE `project_name` = ? AND path IN (";
+            "DELETE FROM `url_index_store` " +
+                    "WHERE `project_name` = ? AND path IN (";
 
     private final String projectName;
     private final String[] paths;
@@ -23,7 +24,9 @@ public class DeleteFilesForProjectSQLUpdate implements SQLUpdate {
 
     @Override
     public String getSQL() {
-        StringBuilder sb = new StringBuilder(DELETE_URL_INDEXES_FOR_PROJECT_NAME);
+        StringBuilder sb = new StringBuilder(
+                DELETE_URL_INDEXES_FOR_PROJECT_NAME
+        );
         for (int i = 0; i < paths.length; i++) {
             sb.append("?");
             if (i < paths.length - 1) {
@@ -35,7 +38,9 @@ public class DeleteFilesForProjectSQLUpdate implements SQLUpdate {
     }
 
     @Override
-    public void addParametersToStatement(PreparedStatement statement) throws SQLException {
+    public void addParametersToStatement(
+            PreparedStatement statement
+    ) throws SQLException {
         statement.setString(1, projectName);
         for (int i = 0; i < paths.length; i++) {
             statement.setString(i + 2, paths[i]);

+ 9 - 2
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/db/sqlite/update/insert/AddURLIndexSQLUpdate.java

@@ -11,7 +11,12 @@ import java.sql.SQLException;
 public class AddURLIndexSQLUpdate implements SQLUpdate {
 
     private static final String ADD_URL_INDEX =
-            "INSERT OR REPLACE INTO `url_index_store` (`project_name`, `url`, `path`) VALUES (?, ?, ?);\n";
+            "INSERT OR REPLACE INTO `url_index_store`(" +
+                    "`project_name`, " +
+                    "`url`, " +
+                    "`path`" +
+            ") VALUES " +
+            "(?, ?, ?)\n";
 
     private final String projectName;
     private final String url;
@@ -29,7 +34,9 @@ public class AddURLIndexSQLUpdate implements SQLUpdate {
     }
 
     @Override
-    public void addParametersToStatement(PreparedStatement statement) throws SQLException {
+    public void addParametersToStatement(
+            PreparedStatement statement
+    ) throws SQLException {
         statement.setString(1, projectName);
         statement.setString(2, url);
         statement.setString(3, path);

+ 47 - 0
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/db/sqlite/update/insert/SetProjectLastAccessedTime.java

@@ -0,0 +1,47 @@
+package uk.ac.ic.wlgitbridge.bridge.db.sqlite.update.insert;
+
+import uk.ac.ic.wlgitbridge.bridge.db.sqlite.SQLUpdate;
+
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.sql.Timestamp;
+
+/**
+ * Created by winston on 23/08/2016.
+ */
+public class SetProjectLastAccessedTime implements SQLUpdate {
+
+    private static final String SET_PROJECT_LAST_ACCESSED_TIME =
+            "INSERT OR REPLACE INTO `swap_table`(\n" +
+            "        `project_name`,\n" +
+            "        `last_accessed`\n" +
+            ") VALUES (\n" +
+            "        ?,\n" +
+            "        ?\n" +
+            ")";
+
+    private final String projectName;
+    private final Timestamp lastAccessed;
+
+    public SetProjectLastAccessedTime(
+            String projectName,
+            Timestamp lastAccessed
+    ) {
+        this.projectName = projectName;
+        this.lastAccessed = lastAccessed;
+    }
+
+    @Override
+    public String getSQL() {
+        return SET_PROJECT_LAST_ACCESSED_TIME;
+    }
+
+    @Override
+    public void addParametersToStatement(
+            PreparedStatement statement
+    ) throws SQLException {
+        statement.setString(1, projectName);
+        statement.setTimestamp(2, lastAccessed);
+    }
+
+}

+ 2 - 1
services/git-bridge/src/main/java/uk/ac/ic/wlgitbridge/bridge/db/sqlite/update/insert/SetProjectSQLUpdate.java

@@ -11,7 +11,8 @@ import java.sql.SQLException;
 public class SetProjectSQLUpdate implements SQLUpdate {
 
     private static final String SET_PROJECT =
-            "INSERT OR REPLACE INTO `projects`(`name`, `version_id`) VALUES (?, ?);\n";
+            "INSERT OR REPLACE INTO `projects`(`name`, `version_id`) " +
+                    "VALUES (?, ?);\n";
 
     private final String projectName;
     private final int versionID;

+ 88 - 0
services/git-bridge/src/test/java/uk/ac/ic/wlgitbridge/bridge/db/sqlite/SqliteDBStoreTest.java

@@ -0,0 +1,88 @@
+package uk.ac.ic.wlgitbridge.bridge.db.sqlite;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import java.io.IOException;
+import java.sql.Timestamp;
+import java.time.LocalDateTime;
+import java.time.temporal.ChronoUnit;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+/**
+ * Created by winston on 23/08/2016.
+ */
+public class SqliteDBStoreTest {
+
+    private SqliteDBStore dbStore;
+
+    @Before
+    public void setup() throws IOException {
+        TemporaryFolder tmpFolder = new TemporaryFolder();
+        tmpFolder.create();
+        dbStore = new SqliteDBStore(tmpFolder.newFile("dbStore.db"));
+    }
+
+    @Test
+    public void swapTableStartsOutEmpty() {
+        assertNull(dbStore.getOldestUnswappedProject());
+    }
+
+    @Test
+    public void testGetOldestUnswappedProject() {
+        dbStore.setLatestVersionForProject("older", 3);
+        dbStore.setLastAccessedTime(
+                "older",
+                Timestamp.valueOf(
+                        LocalDateTime.now().minus(5, ChronoUnit.SECONDS)
+                )
+        );
+        dbStore.setLatestVersionForProject("asdf", 1);
+        dbStore.setLastAccessedTime(
+                "asdf",
+                Timestamp.valueOf(
+                        LocalDateTime.now().minus(1, ChronoUnit.SECONDS)
+                )
+        );
+        assertEquals("older", dbStore.getOldestUnswappedProject());
+        dbStore.setLastAccessedTime(
+                "older",
+                Timestamp.valueOf(
+                        LocalDateTime.now()
+                )
+        );
+        assertEquals("asdf", dbStore.getOldestUnswappedProject());
+    }
+
+    @Test
+    public void noOldestProjectIfAllEvicated() {
+        dbStore.setLatestVersionForProject("older", 3);
+        dbStore.setLastAccessedTime("older", null);
+        assertNull(dbStore.getOldestUnswappedProject());
+    }
+
+    @Test
+    public void nullLastAccessedTimesDoNotCount() {
+        dbStore.setLatestVersionForProject("older", 2);
+        dbStore.setLastAccessedTime(
+                "older",
+                Timestamp.valueOf(
+                        LocalDateTime.now().minus(5, ChronoUnit.SECONDS)
+                )
+        );
+        dbStore.setLatestVersionForProject("newer", 3);
+        dbStore.setLastAccessedTime(
+                "newer",
+                Timestamp.valueOf(
+                        LocalDateTime.now()
+                )
+        );
+        assertEquals("older", dbStore.getOldestUnswappedProject());
+        dbStore.setLastAccessedTime("older", null);
+        assertEquals("newer", dbStore.getOldestUnswappedProject());
+    }
+
+}