package diskCacheV111.services.space; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.dao.DataAccessException; import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.dao.support.DataAccessUtils; import org.springframework.jdbc.JdbcUpdateAffectedIncorrectNumberOfRowsException; import org.springframework.jdbc.core.support.JdbcDaoSupport; import org.springframework.jdbc.support.GeneratedKeyHolder; import org.springframework.jdbc.support.KeyHolder; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.Set; import java.util.stream.Stream; import diskCacheV111.util.AccessLatency; import diskCacheV111.util.PnfsId; import diskCacheV111.util.RetentionPolicy; import diskCacheV111.util.VOInfo; import org.dcache.util.SqlGlob; import static java.util.Arrays.asList; import static java.util.stream.Collectors.joining; @Repository public class JdbcSpaceManagerDatabase extends JdbcDaoSupport implements SpaceManagerDatabase { private static final Logger LOGGER = LoggerFactory.getLogger(JdbcSpaceManagerDatabase.class); private static final String RETENTION_POLICY_TABLE = "srmretentionpolicy"; private static final String ACCESS_LATENCY_TABLE = "srmaccesslatency"; /* Table "public.srmlinkgroup" Column | Type | Modifiers ----------------------+--------------------------+----------- id | bigint | not null name | character varying(32672) | availablespaceinbytes| bigint | not null lastupdatetime | bigint | onlineallowed | integer | nearlineallowed | integer | replicaallowed | integer | outputallowed | integer | custodialallowed | integer | reservedspaceinbytes | bigint | not null */ private static final String LINKGROUP_TABLE = "srmlinkgroup"; /* Table "public.srmlinkgroupvos" Column | Type | Modifiers -------------+--------------------------+----------- vogroup | character varying(32672) | not null vorole | character varying(32672) | not null linkgroupid | bigint | not null */ private static final String LINKGROUP_VO_TABLE = "srmlinkgroupvos"; /* Column | Type | Modifiers ------------------------+--------------------------+----------- id | bigint | not null vogroup | character varying(32672) | vorole | character varying(32672) | retentionpolicy | integer | accesslatency | integer | linkgroupid | bigint | not null sizeinbytes | bigint | not null creationtime | bigint | not null expirationtime | bigint | description | character varying(32672) | state | integer | not null usedspaceinbytes | bigint | not null allocatedspaceinbytes | bigint | not null */ private static final String SPACE_TABLE = "srmspace"; /* Table "public.srmspacefile" Column | Type | Modifiers --------------------+--------------------------+----------- id | bigint | not null vogroup | character varying(32672) | vorole | character varying(32672) | spacereservationid | bigint | not null sizeinbytes | bigint | not null creationtime | bigint | not null pnfsid | character varying(36) | unique state | integer | not null */ private static final String SPACEFILE_TABLE = "srmspacefile"; public void init() throws DataAccessException { insertRetentionPolicies(); insertAccessLatencies(); } private void insertRetentionPolicies() throws DataAccessException { RetentionPolicy[] policies = RetentionPolicy.getAllPolicies(); Long cnt = getJdbcTemplate().queryForObject("SELECT count(*) FROM " + RETENTION_POLICY_TABLE, Long.class); if (cnt == policies.length) { return; } for (RetentionPolicy policy : policies) { try { getJdbcTemplate().update("INSERT INTO " + RETENTION_POLICY_TABLE + " (id, name) VALUES (?,?)", policy.getId(), policy.toString()); } catch (DataAccessException sqle) { LOGGER.error("insert retention policy {} failed: {}", policy, sqle.getMessage()); } } } private void insertAccessLatencies() throws DataAccessException { AccessLatency[] latencies = AccessLatency.getAllLatencies(); Long cnt = getJdbcTemplate().queryForObject( "SELECT count(*) from " + ACCESS_LATENCY_TABLE, Long.class); if (cnt == latencies.length) { return; } for (AccessLatency latency : latencies) { try { getJdbcTemplate().update("INSERT INTO " + ACCESS_LATENCY_TABLE + " (id, name) VALUES (?,?)", latency.getId(), latency.toString()); } catch (DataAccessException sqle) { LOGGER.error("insert access latency {} failed: {}", latency, sqle.getMessage()); } } } @Override public void removeFile(long fileId) throws DataAccessException { int rc = getJdbcTemplate().update("DELETE FROM " + SPACEFILE_TABLE + " WHERE id=?", fileId); if (rc > 1) { throw new JdbcUpdateAffectedIncorrectNumberOfRowsException("delete returned row count = " + rc, 1, rc); } } @Override @Transactional(propagation = Propagation.MANDATORY, noRollbackFor = EmptyResultDataAccessException.class) public Space selectSpaceForUpdate(long id) throws DataAccessException { try { return getJdbcTemplate().queryForObject( "SELECT * FROM " + SPACE_TABLE + " WHERE id = ? FOR UPDATE", this::toSpace, id); } catch (EmptyResultDataAccessException e) { throw new EmptyResultDataAccessException("No such space reservation: " + id, 1, e); } } @Override @Transactional(propagation = Propagation.MANDATORY, noRollbackFor = EmptyResultDataAccessException.class) public File selectFileForUpdate(PnfsId pnfsId) throws DataAccessException { try { return getJdbcTemplate().queryForObject( "SELECT * FROM " + SPACEFILE_TABLE + " WHERE pnfsid = ? FOR UPDATE ", this::toFile, pnfsId.toString()); } catch (EmptyResultDataAccessException e) { throw new EmptyResultDataAccessException("Space reservation for " + pnfsId + " not found.", 1, e); } } @Override @Transactional(propagation = Propagation.MANDATORY, noRollbackFor = EmptyResultDataAccessException.class) public File selectFileForUpdate(long id) throws DataAccessException { try { return getJdbcTemplate().queryForObject( "SELECT * FROM " + SPACEFILE_TABLE + " WHERE id = ? FOR UPDATE ", this::toFile, id); } catch (EmptyResultDataAccessException e) { throw new EmptyResultDataAccessException("No such file id: " + id, 1, e); } } @Override public Space updateSpace(Space space) throws DataAccessException { getJdbcTemplate().update( "UPDATE " + SPACE_TABLE + " SET vogroup=?,vorole=?,retentionpolicy=?,accesslatency=?,linkgroupid=?,sizeinbytes=?," + " creationtime=?,expirationTime=?,description=?,state=? WHERE id=?", space.getVoGroup(), space.getVoRole(), space.getRetentionPolicy().getId(), space.getAccessLatency().getId(), space.getLinkGroupId(), space.getSizeInBytes(), space.getCreationTime(), space.getExpirationTime(), space.getDescription(), space.getState().getStateId(), space.getId()); return space; } @Override @Transactional public long updateLinkGroup(final String linkGroupName, final long freeSpace, final long updateTime, final boolean onlineAllowed, final boolean nearlineAllowed, final boolean replicaAllowed, final boolean outputAllowed, final boolean custodialAllowed, VOInfo[] linkGroupVOs) throws DataAccessException { long id; try { /* FOR UPDATE to avoid lock upgrade below */ id = getJdbcTemplate().queryForObject("SELECT id FROM " + LINKGROUP_TABLE + " WHERE name = ? FOR UPDATE", Long.class, linkGroupName); getJdbcTemplate().update( "UPDATE " + LINKGROUP_TABLE + " SET availableSpaceInBytes=?-reservedSpaceInBytes,lastUpdateTime=?,onlineAllowed=?,nearlineAllowed=?," + "replicaAllowed=?,outputAllowed=?,custodialAllowed=? WHERE id = ?", freeSpace, updateTime, (onlineAllowed ? 1 : 0), (nearlineAllowed ? 1 : 0), (replicaAllowed ? 1 : 0), (outputAllowed ? 1 : 0), (custodialAllowed ? 1 : 0), id); } catch (EmptyResultDataAccessException e) { try { KeyHolder keyHolder = new GeneratedKeyHolder(); getJdbcTemplate().update( con -> { /* Note that neither prepareStatement(String, String[]) nor prepareStatement(String, int[]) * work for us: The former suffers from different interpretations of case in HSQLDB and * PostgreSQL and the latter is not support by the PostgreSQL JDBC driver. */ PreparedStatement stmt = con.prepareStatement( "INSERT INTO " + LINKGROUP_TABLE + " (name, availableSpaceInBytes, lastUpdateTime, onlineAllowed," + " nearlineAllowed, replicaAllowed, outputAllowed, custodialAllowed,reservedspaceinbytes)" + " VALUES (?,?,?,?,?,?,?,?,?)", Statement.RETURN_GENERATED_KEYS); stmt.setString(1, linkGroupName); stmt.setLong(2, freeSpace); stmt.setLong(3, updateTime); stmt.setInt(4, (onlineAllowed ? 1 : 0)); stmt.setInt(5, (nearlineAllowed ? 1 : 0)); stmt.setInt(6, (replicaAllowed ? 1 : 0)); stmt.setInt(7, (outputAllowed ? 1 : 0)); stmt.setInt(8, (custodialAllowed ? 1 : 0)); stmt.setLong(9, (long) 0); return stmt; }, keyHolder); id = (Long) keyHolder.getKeys().get("id"); } catch (DataAccessException e1) { LOGGER.error("failed to insert linkgroup {}: {}", linkGroupName, e.getMessage()); throw e1; } } final Set<VOInfo> deleteVOs = new HashSet<>(); final Set<VOInfo> insertVOs = new HashSet<>(); if (linkGroupVOs != null) { insertVOs.addAll(asList(linkGroupVOs)); } getJdbcTemplate().query("SELECT VOGroup,VORole FROM " + LINKGROUP_VO_TABLE + " WHERE linkGroupId=?", (ResultSet rs) -> { String nextVOGroup = rs.getString(1); String nextVORole = rs.getString(2); VOInfo nextVO = new VOInfo(nextVOGroup, nextVORole); if (!insertVOs.remove(nextVO)) { deleteVOs.add(nextVO); } }, id); for (VOInfo nextVo : insertVOs) { getJdbcTemplate().update( "INSERT INTO " + LINKGROUP_VO_TABLE + " ( VOGroup, VORole, linkGroupId ) VALUES ( ? , ? , ? )", nextVo.getVoGroup(), nextVo.getVoRole(), id); } for (VOInfo nextVo : deleteVOs) { getJdbcTemplate().update( "DELETE FROM " + LINKGROUP_VO_TABLE + " WHERE VOGroup = ? AND VORole = ? AND linkGroupId = ? ", nextVo.getVoGroup(), nextVo.getVoRole(), id); } return id; } @Override public Space insertSpace(final String voGroup, final String voRole, final RetentionPolicy retentionPolicy, final AccessLatency accessLatency, final long linkGroupId, final long sizeInBytes, final long lifetime, final String description, final SpaceState state, final long used, final long allocated) throws DataAccessException { final long creationTime = System.currentTimeMillis(); KeyHolder keyHolder = new GeneratedKeyHolder(); int rc = getJdbcTemplate().update( con -> { /* Note that neither prepareStatement(String, String[]) nor prepareStatement(String, int[]) * work for us: The former suffers from different interpretations of case in HSQLDB and * PostgreSQL and the latter is not support by the PostgreSQL JDBC driver. */ PreparedStatement stmt = con.prepareStatement( "INSERT INTO " + SPACE_TABLE + " (vogroup,vorole,retentionpolicy,accesslatency,linkgroupid," + "sizeinbytes,creationtime,expirationtime,description,state,usedspaceinbytes,allocatedspaceinbytes)" + " VALUES (?,?,?,?,?,?,?,?,?,?,?,?)", Statement.RETURN_GENERATED_KEYS); stmt.setString(1, voGroup); stmt.setString(2, voRole); stmt.setInt(3, retentionPolicy == null ? 0 : retentionPolicy.getId()); stmt.setInt(4, accessLatency == null ? 0 : accessLatency.getId()); stmt.setLong(5, linkGroupId); stmt.setLong(6, sizeInBytes); stmt.setLong(7, creationTime); stmt.setObject(8, (lifetime == -1) ? null : creationTime + lifetime); stmt.setString(9, description); stmt.setInt(10, state.getStateId()); stmt.setLong(11, used); stmt.setLong(12, allocated); return stmt; }, keyHolder); if (rc != 1) { throw new JdbcUpdateAffectedIncorrectNumberOfRowsException("insert returned row count =" + rc, 1, rc); } return new Space((Long) keyHolder.getKeys().get("id"), voGroup, voRole, retentionPolicy, accessLatency, linkGroupId, sizeInBytes, creationTime, (lifetime == -1) ? null : creationTime + lifetime, description, state, used, allocated); } @Override public Space getSpace(long id) throws DataAccessException { try { return getJdbcTemplate().queryForObject( "SELECT * FROM " + SPACE_TABLE + " WHERE id=?", this::toSpace, id); } catch (EmptyResultDataAccessException e) { throw new EmptyResultDataAccessException("No such space reservation: " + id, 1, e); } } @Override public LinkGroup getLinkGroup(long id) throws DataAccessException { try { return getJdbcTemplate().queryForObject( "SELECT * FROM " + LINKGROUP_TABLE + " WHERE id = ?", this::toLinkGroup, id); } catch (EmptyResultDataAccessException e) { throw new EmptyResultDataAccessException("No such link group: " + id, 1, e); } } @Override public LinkGroup getLinkGroupByName(String name) throws DataAccessException { try { return getJdbcTemplate().queryForObject( "SELECT * FROM " + LINKGROUP_TABLE + " WHERE name = ?", this::toLinkGroup, name); } catch (EmptyResultDataAccessException e) { throw new EmptyResultDataAccessException("No such link group: " + name, 1, e); } } @Override public void updateFile(File f) throws DataAccessException { int rc = getJdbcTemplate().update( "UPDATE " + SPACEFILE_TABLE + " SET vogroup=?, vorole=?, sizeinbytes=?, pnfsid=?, state=? WHERE id=?", f.getVoGroup(), f.getVoRole(), f.getSizeInBytes(), Objects.toString(f.getPnfsId(), null), f.getState().getStateId(), f.getId()); if (rc != 1) { throw new JdbcUpdateAffectedIncorrectNumberOfRowsException("Update failed, row count=" + rc, 1, rc); } } @Override public File findFile(PnfsId pnfsId) throws DataAccessException { List<File> results = getJdbcTemplate().query("SELECT * FROM " + SPACEFILE_TABLE + " WHERE pnfsId=?", this::toFile, pnfsId.toString()); return DataAccessUtils.singleResult(results); } @Override public LinkGroupCriterion linkGroups() { return new LinkGroupCriterionImpl(); } @Override public List<LinkGroup> get(LinkGroupCriterion criterion) { JdbcCriterion c = (JdbcCriterion) criterion; return getJdbcTemplate().query( "SELECT * from " + LINKGROUP_TABLE + " WHERE " + c.getPredicate(), c.getArguments(), this::toLinkGroup); } @Override public SpaceCriterion spaces() { return new SpaceCriterionImpl(); } @Override public List<Space> get(SpaceCriterion criterion, Integer limit) { JdbcCriterion c = (JdbcCriterion) criterion; return getJdbcTemplate().query( "SELECT * FROM " + SPACE_TABLE + " WHERE " + c.getPredicate() + (limit != null ? " LIMIT " + limit : ""), c.getArguments(), this::toSpace); } @Override public List<Long> getSpaceTokensOf(SpaceCriterion criterion) { JdbcCriterion c = (JdbcCriterion) criterion; return getJdbcTemplate().queryForList( "SELECT id FROM " + SPACE_TABLE + " WHERE " + c.getPredicate(), c.getArguments(), Long.class); } @Override public int count(SpaceCriterion criterion) { JdbcCriterion c = (JdbcCriterion) criterion; return getJdbcTemplate().queryForObject( "SELECT count(*) FROM " + SPACE_TABLE + " WHERE " + c.getPredicate(), c.getArguments(), Integer.class); } @Override public FileCriterion files() { return new FileCriterionImpl(); } @Override public List<File> get(FileCriterion criterion, Integer limit) { JdbcCriterion c = (JdbcCriterion) criterion; return getJdbcTemplate().query( "SELECT * FROM " + SPACEFILE_TABLE + " WHERE " + c.getPredicate() + (limit != null ? " LIMIT " + limit : ""), c.getArguments(), this::toFile); } @Override public int count(FileCriterion criterion) { JdbcCriterion c = (JdbcCriterion) criterion; return getJdbcTemplate().queryForObject( "SELECT count(*) FROM " + SPACEFILE_TABLE + " WHERE " + c.getPredicate(), c.getArguments(), Integer.class); } @Override public int remove(FileCriterion criterion) { JdbcCriterion c = (JdbcCriterion) criterion; return getJdbcTemplate().update( "DELETE FROM " + SPACEFILE_TABLE + " WHERE " + c.getPredicate(), c.getArguments()); } @Override public int remove(SpaceCriterion criterion) { JdbcCriterion c = (JdbcCriterion) criterion; return getJdbcTemplate().update( "DELETE FROM " + SPACE_TABLE + " WHERE " + c.getPredicate(), c.getArguments()); } @Override public long insertFile(final long reservationId, final String voGroup, final String voRole, final long sizeInBytes, final PnfsId pnfsId, final FileState state) throws DataAccessException, SpaceException { final long creationTime = System.currentTimeMillis(); Space space = selectSpaceForUpdate(reservationId); long currentTime = System.currentTimeMillis(); if (space.getExpirationTime() != null && space.getExpirationTime() <= currentTime) { throw new SpaceExpiredException("space with id=" + reservationId + " has expired"); } if (space.getState() == SpaceState.EXPIRED) { throw new SpaceExpiredException("space with id=" + reservationId + " has expired"); } if (space.getState() == SpaceState.RELEASED) { throw new SpaceReleasedException("space with id=" + reservationId + " was released"); } if (space.getAvailableSpaceInBytes() < sizeInBytes) { throw new NoFreeSpaceException("space with id=" + reservationId + " does not have enough space"); } KeyHolder keyHolder = new GeneratedKeyHolder(); int rc = getJdbcTemplate().update( con -> { /* Note that neither prepareStatement(String, String[]) nor prepareStatement(String, int[]) * work for us: The former suffers from different interpretations of case in HSQLDB and * PostgreSQL and the latter is not support by the PostgreSQL JDBC driver. */ PreparedStatement stmt = con.prepareStatement( "INSERT INTO " + SPACEFILE_TABLE + " (vogroup,vorole,spacereservationid,sizeinbytes,creationtime,pnfsid,state) " + " VALUES (?,?,?,?,?,?,?)", Statement.RETURN_GENERATED_KEYS); stmt.setString(1, voGroup); stmt.setString(2, voRole); stmt.setLong(3, reservationId); stmt.setLong(4, sizeInBytes); stmt.setLong(5, creationTime); stmt.setString(6, Objects.toString(pnfsId, null)); stmt.setInt(7, state.getStateId()); return stmt; }, keyHolder); if (rc != 1) { throw new JdbcUpdateAffectedIncorrectNumberOfRowsException("insert returned row count =" + rc, 1, rc); } return (Long) keyHolder.getKeys().get("id"); } @Override public void expire(SpaceCriterion criterion) { JdbcCriterion c = (JdbcCriterion) criterion; getJdbcTemplate().update( "UPDATE " + SPACE_TABLE + " SET state = " + SpaceState.EXPIRED.getStateId() + " WHERE " + c.getPredicate(), c.getArguments()); } private static class JdbcCriterion { final StringBuilder predicate = new StringBuilder(); final List<Object> arguments = new ArrayList<>(); protected void addClause(String clause, Object... arguments) { if (predicate.length() > 0) { predicate.append(" AND "); } predicate.append(clause); this.arguments.addAll(asList(arguments)); } protected void whereFieldMatches(String field, SqlGlob pattern) { if (pattern.isGlob()) { addClause(field + "LIKE ?", pattern.toSql()); } else { addClause(field + " = ?", pattern.toString()); } } public String getPredicate() { return predicate.length() == 0 ? "true" : predicate.toString(); } public Object[] getArguments() { return arguments.toArray(new Object[arguments.size()]); } } private static class LinkGroupCriterionImpl extends JdbcCriterion implements LinkGroupCriterion { @Override public LinkGroupCriterion whereUpdateTimeAfter(long latestLinkGroupUpdateTime) { addClause("lastupdatetime >= ?", latestLinkGroupUpdateTime); return this; } @Override public LinkGroupCriterion allowsAccessLatency(AccessLatency al) { if (al == AccessLatency.NEARLINE) { addClause("nearlineallowed=1"); } else if (al == AccessLatency.ONLINE) { addClause("onlineallowed=1"); } return this; } @Override public LinkGroupCriterion allowsRetentionPolicy(RetentionPolicy rp) { if (rp == RetentionPolicy.OUTPUT) { addClause("outputallowed=1"); } else if (rp == RetentionPolicy.REPLICA) { addClause("replicaallowed=1"); } else if (rp == RetentionPolicy.CUSTODIAL) { addClause("custodialallowed=1"); } return this; } @Override public LinkGroupCriterion whereNameMatches(SqlGlob name) { whereFieldMatches("name", name); return this; } @Override public LinkGroupCriterion hasAvailable(long bytes) { addClause("availablespaceinbytes >= " + bytes); return this; } } private static class SpaceCriterionImpl extends JdbcCriterion implements SpaceCriterion { @Override public SpaceCriterion whereStateIsIn(SpaceState... states) { addClause(Stream.of(states) .mapToInt(SpaceState::getStateId) .mapToObj(String::valueOf) .collect(joining(",", "state IN (", ")"))); return this; } @Override public SpaceCriterion whereRetentionPolicyIs(RetentionPolicy rp) { addClause("retentionpolicy = ?", rp.getId()); return this; } @Override public SpaceCriterion whereAccessLatencyIs(AccessLatency al) { addClause("accesslatency = ?", al.getId()); return this; } @Override public SpaceCriterion whereDescriptionMatches(SqlGlob desc) { whereFieldMatches("description", desc); return this; } @Override public SpaceCriterion whereRoleMatches(SqlGlob role) { whereFieldMatches("vorole", role); return this; } @Override public SpaceCriterion whereGroupMatches(SqlGlob group) { whereFieldMatches("vogroup", group); return this; } @Override public SpaceCriterion whereTokenIs(long token) { addClause("id = ?", token); return this; } @Override public SpaceCriterion thatNeverExpire() { addClause("expirationtime IS NULL"); return this; } @Override public SpaceCriterion whereLinkGroupIs(long id) { addClause("linkgroupid = ?", id); return this; } @Override public SpaceCriterion whereGroupIs(String group) { addClause("vogroup = ?", group); return this; } @Override public SpaceCriterion whereRoleIs(String role) { addClause("vorole = ?", role); return this; } @Override public SpaceCriterion whereDescriptionIs(String description) { addClause("description = ?", description); return this; } @Override public SpaceCriterion thatExpireBefore(long millis) { addClause("expirationtime < ?", millis); return this; } @Override public SpaceCriterion thatHaveNoFiles() { addClause("NOT EXISTS (SELECT * FROM " + SPACEFILE_TABLE + " WHERE spacereservationid = srmspace.id)"); return this; } } private static class FileCriterionImpl extends JdbcCriterion implements FileCriterion { @Override public FileCriterion whereGroupMatches(SqlGlob group) { whereFieldMatches("group", group); return this; } @Override public FileCriterion whereRoleMatches(SqlGlob role) { whereFieldMatches("role", role); return this; } @Override public FileCriterion whereSpaceTokenIs(Long token) { addClause("spacereservationid = ?", token); return this; } @Override public FileCriterion whereStateIsIn(FileState... states) { addClause(Stream.of(states) .mapToInt(FileState::getStateId) .mapToObj(String::valueOf) .collect(joining(",", "state IN (", ")"))); return this; } @Override public FileCriterion wherePnfsIdIs(PnfsId pnfsId) { addClause("pnfsid = ?", pnfsId.toString()); return this; } @Override public FileCriterion in(SpaceCriterion spaceCriterion) { JdbcCriterion criterion = (JdbcCriterion) spaceCriterion; addClause("spacereservationid IN (SELECT id FROM " + SPACE_TABLE + " WHERE " + criterion.getPredicate() + ")", criterion.getArguments()); return this; } @Override public FileCriterion whereCreationTimeIsBefore(long millis) { addClause("creationtime < ?", millis); return this; } } private Space toSpace(ResultSet set, int rowNum) throws SQLException { return new Space(set.getLong("id"), set.getString("vogroup"), set.getString("vorole"), RetentionPolicy.getRetentionPolicy(set.getInt("retentionPolicy")), AccessLatency.getAccessLatency(set.getInt("accessLatency")), set.getLong("linkgroupid"), set.getLong("sizeinbytes"), set.getLong("creationtime"), toNull(set.getLong("expirationtime"), set.wasNull()), set.getString("description"), SpaceState.valueOf(set.getInt("state")), set.getLong("usedspaceinbytes"), set.getLong("allocatedspaceinbytes")); } private LinkGroup toLinkGroup(ResultSet set, int rowNum) throws SQLException { LinkGroup lg = new LinkGroup(); lg.setId(set.getLong("id")); lg.setName(set.getString("name")); lg.setAvailableSpace(set.getLong("availablespaceinbytes")); lg.setUpdateTime(set.getLong("lastupdatetime")); lg.setOnlineAllowed(set.getBoolean("onlineallowed")); lg.setNearlineAllowed(set.getBoolean("nearlineallowed")); lg.setReplicaAllowed(set.getBoolean("replicaallowed")); lg.setOutputAllowed(set.getBoolean("outputallowed")); lg.setCustodialAllowed(set.getBoolean("custodialallowed")); lg.setReservedSpace(set.getLong("reservedspaceinbytes")); List<VOInfo> vos = getJdbcTemplate().query( "SELECT voGroup,voRole FROM " + LINKGROUP_VO_TABLE + " WHERE linkGroupId=?", (vo, i) -> new VOInfo(vo.getString("vogroup"), vo.getString("vorole")), lg.getId()); lg.setVOs(vos.toArray(new VOInfo[vos.size()])); return lg; } private File toFile(ResultSet set, int rowNum) throws SQLException { String pnfsId = set.getString("pnfsId"); return new File(set.getLong("id"), set.getString("vogroup"), set.getString("vorole"), set.getLong("spacereservationid"), set.getLong("sizeinbytes"), set.getLong("creationtime"), (pnfsId != null) ? new PnfsId(pnfsId) : null, FileState.valueOf(set.getInt("state"))); } private static <T> T toNull(T value, boolean makeNull) { return makeNull ? null : value; } }