diff --git a/src/main/java/it/inaf/ia2/transfer/persistence/FileDAO.java b/src/main/java/it/inaf/ia2/transfer/persistence/FileDAO.java index b37ac9ed4c0e54aafa3b238da97a6cce2eabb926..a2227d5e211c5209ba131e7099c41d3a58feb730 100644 --- a/src/main/java/it/inaf/ia2/transfer/persistence/FileDAO.java +++ b/src/main/java/it/inaf/ia2/transfer/persistence/FileDAO.java @@ -18,6 +18,8 @@ import java.util.Collections; import java.util.List; import java.util.Optional; import javax.sql.DataSource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.jdbc.core.JdbcTemplate; @@ -26,6 +28,8 @@ import org.springframework.stereotype.Repository; @Repository public class FileDAO { + private static final Logger LOG = LoggerFactory.getLogger(FileDAO.class); + @Value("${upload_location_id}") private int uploadLocationId; @@ -121,6 +125,37 @@ public class FileDAO { } + public Long getRemainingQuota(String parentVosPath) { + + String sql = "WITH quota_info AS (\n" + + " SELECT p.quota, get_vos_path(p.node_id) AS parent_vos_path\n" + + " FROM node p\n" + + " JOIN node n ON p.path @> n.path\n" + + " WHERE n.node_id = id_from_vos_path(?) AND p.quota IS NOT NULL\n" + + " ORDER BY nlevel(p.path) DESC LIMIT 1\n" + + ")\n" + + "SELECT AVG(qi.quota)::bigint - SUM(c.content_length) AS remaining_quota\n" + + "FROM node c\n" + + "JOIN node n ON n.path @> c.path\n" + + "JOIN quota_info qi ON n.node_id = id_from_vos_path(qi.parent_vos_path)\n" + + "WHERE c.type <> 'container'"; + + return jdbcTemplate.query(conn -> { + PreparedStatement ps = conn.prepareStatement(sql); + ps.setString(1, parentVosPath); + return ps; + }, rs -> { + if (rs.next()) { + long remainingQuota = rs.getLong(1); + if (!rs.wasNull()) { + return remainingQuota; + } + } + LOG.warn("Quota not defined for path {}", parentVosPath); + return null; + }); + } + // TODO: set maximum list size or use stream to avoid memory issues public List getArchiveFileInfos(List vosPaths) { diff --git a/src/test/java/it/inaf/ia2/transfer/persistence/FileDAOTest.java b/src/test/java/it/inaf/ia2/transfer/persistence/FileDAOTest.java index cf4098b54abd83928e1e489ca13bcbd7eba9d996..7b8dcc08a9e86fd5fd9fc855de93d8214ea3f55a 100644 --- a/src/test/java/it/inaf/ia2/transfer/persistence/FileDAOTest.java +++ b/src/test/java/it/inaf/ia2/transfer/persistence/FileDAOTest.java @@ -11,6 +11,7 @@ import java.util.List; import java.util.Optional; import javax.sql.DataSource; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -66,4 +67,17 @@ public class FileDAOTest { assertEquals("/home/username1/retrieve/subdir1/file4", fileInfos.get(4).getOsPath()); assertEquals("portal-file", fileInfos.get(5).getVirtualName()); } + + @Test + public void testGetRemainingQuota() { + + assertEquals(600000l, dao.getRemainingQuota("/test_quota")); + assertEquals(200000l, dao.getRemainingQuota("/test_quota/subdir")); + } + + @Test + public void testGetNoQuota() { + + assertNull(dao.getRemainingQuota("/")); + } } diff --git a/src/test/resources/test-data.sql b/src/test/resources/test-data.sql index 7fe0170c69ddd90bd3828f415d3c27e4cb2733e4..0343db18ce2fd63a53efd0c3a662cd20552249a7 100644 --- a/src/test/resources/test-data.sql +++ b/src/test/resources/test-data.sql @@ -31,6 +31,12 @@ INSERT INTO node (parent_path, parent_relative_path, name, type, creator_id, loc ('5.8', '8', 'file4', 'data', 'user1', 1, true), ('5.8', '8', 'portal-file', 'data', 'user1', 4, true); +INSERT INTO node (parent_path, parent_relative_path, name, type, creator_id, content_length, quota) VALUES +('', NULL, 'test_quota', 'container', 'user1', 0, 900000), +('12', NULL, 'subdir', 'container', 'user1', 0, 500000), +('12.13', NULL, 'file1', 'data', 'user1', 100000, 500000), +('12.13', NULL, 'file2', 'data', 'user1', 200000, 500000); + DELETE FROM job; INSERT INTO job (job_id, owner_id, job_type, phase, start_time, end_time, creation_time, job_info, results) VALUES ('pippo1', 'user1', 'pullFromVoSpace', 'ARCHIVED', NULL, NULL, '2011-06-22 19:10:25', NULL, NULL);