Skip to content

Commit

Permalink
spacemanager: Maintain aggregate columns with database triggers
Browse files Browse the repository at this point in the history
Moves the logic to maintain aggregate columns in srmlinkgroup and srmspace from
Java code to database triggers. Adds not-null constraints to several space
manager database columns. This may take a little while to apply on large
databases.

The schema modifications are not compatible with older versions. Should a
downgrade be needed, the schema modifications have to be rolled back using
'dcache database rollback <tag> SrmSpaceManager@<domain>' or 'dcache database
rollback <date> SrmSpaceManager@<domain>'. The former requires that a tag was
created before upgrade (this is recommended). Should the system be downgraded
without rolling back the schema changes, the space accounting will be
incorrect.

Target: master
Require-notes: yes
Require-book: yes
Acked-by: Dmitry Litvintsev <litvinse@fnal.gov>
Patch: http://rb.dcache.org/r/6370/
  • Loading branch information
gbehrmann committed Jan 10, 2014
1 parent 79cad7f commit 222cae0
Show file tree
Hide file tree
Showing 7 changed files with 430 additions and 300 deletions.
Expand Up @@ -78,10 +78,6 @@ public class LinkGroupIO extends IoPackage<LinkGroup> {
public static final String SELECT_LINKGROUP_VO ="SELECT voGroup,voRole FROM "+LINKGROUP_VO_TABLE+" WHERE linkGroupId=?";
public static final String SELECT_CURRENT_LINKGROUPS = "SELECT * FROM "+ LINKGROUP_TABLE + " where lastUpdateTime >= ?";
public static final String SELECT_ALL_LINKGROUPS = "SELECT * FROM "+ LINKGROUP_TABLE;
public static final String DECREMENT_RESERVED_SPACE = "UPDATE "+LINKGROUP_TABLE+" SET reservedspaceinbytes = reservedspaceinbytes - ? where id=?";
public static final String INCREMENT_RESERVED_SPACE = "UPDATE "+LINKGROUP_TABLE+" SET reservedspaceinbytes = reservedspaceinbytes + ? where id=?";
public static final String DECREMENT_FREE_SPACE = "UPDATE "+LINKGROUP_TABLE+" SET freespaceinbytes = freespaceinbytes - ? where id=?";
public static final String INCREMENT_FREE_SPACE = "UPDATE "+LINKGROUP_TABLE+" SET freespaceinbytes = freespaceinbytes + ? where id=?";
public static final String UPDATE = "UPDATE "+LINKGROUP_TABLE+" SET freeSpaceInBytes=?,lastUpdateTime=?,onlineAllowed=?,nearlineAllowed=?,"+
"replicaAllowed=?,outputAllowed=?,custodialAllowed=? WHERE id = ?";
public static final String SELECT_ALL = "SELECT * FROM "+LINKGROUP_TABLE;
Expand Down
308 changes: 16 additions & 292 deletions modules/dcache/src/main/java/diskCacheV111/services/space/Manager.java

Large diffs are not rendered by default.

Expand Up @@ -88,10 +88,6 @@ public class SpaceReservationIO extends IoPackage<Space> {
" WHERE id = ? AND sizeinbytes-allocatedspaceinbytes >= ? FOR UPDATE ";
public static final String UPDATE_STATUS = "UPDATE "+SRM_SPACE_TABLE+ "SET status=? WHERE id=? ";
public static final String UPDATE_LIFETIME = "UPDATE "+SRM_SPACE_TABLE+ "SET lifetime=? WHERE id=? ";
public static final String DECREMENT_ALLOCATED_SPACE = "UPDATE "+SRM_SPACE_TABLE+" SET allocatedspaceinbytes = allocatedspaceinbytes - ? where id=?";
public static final String INCREMENT_ALLOCATED_SPACE = "UPDATE "+SRM_SPACE_TABLE+" SET allocatedspaceinbytes = allocatedspaceinbytes + ? where id=?";
public static final String DECREMENT_USED_SPACE = "UPDATE "+SRM_SPACE_TABLE+" SET usedspaceinbytes = usedspaceinbytes - ? where id=?";
public static final String INCREMENT_USED_SPACE = "UPDATE "+SRM_SPACE_TABLE+" SET usedspaceinbytes = usedspaceinbytes + ? where id=?";
public static final String SELECT_SPACE_RESERVATIONS_FOR_EXPIRED_FILES="select * from srmspace where id in (select distinct spacereservationid from srmspacefile where (state= "+FileState.RESERVED.getStateId()+" or state = "+ FileState.TRANSFERRING.getStateId() +") and creationtime+lifetime<?)";

public SpaceReservationIO() {
Expand Down
Expand Up @@ -196,4 +196,16 @@
</rollback>
</changeSet>

<changeSet id="5" author="behrmann">
<addNotNullConstraint tableName="srmlinkgroup" columnName="freespaceinbytes"/>
<addNotNullConstraint tableName="srmlinkgroup" columnName="reservedspaceinbytes"/>
<addNotNullConstraint tableName="srmspace" columnName="sizeinbytes"/>
<addNotNullConstraint tableName="srmspace" columnName="usedspaceinbytes"/>
<addNotNullConstraint tableName="srmspace" columnName="allocatedspaceinbytes"/>
<addNotNullConstraint tableName="srmspace" columnName="linkgroupid"/>
<addNotNullConstraint tableName="srmspace" columnName="state"/>
<addNotNullConstraint tableName="srmspacefile" columnName="sizeinbytes"/>
<addNotNullConstraint tableName="srmspacefile" columnName="spacereservationid"/>
<addNotNullConstraint tableName="srmspacefile" columnName="state"/>
</changeSet>
</databaseChangeLog>
Expand Up @@ -3,5 +3,11 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.0.xsd">

<preConditions>
<dbms type="postgresql,hsqldb"/>
</preConditions>

<include file="diskCacheV111/services/space/db/spacemanager.changelog-2.8.xml"/>
<include file="diskCacheV111/services/space/db/spacemanager.changelog-procedures-hsqldb.xml"/>
<include file="diskCacheV111/services/space/db/spacemanager.changelog-procedures-postgresql.xml"/>
</databaseChangeLog>
@@ -0,0 +1,180 @@
<?xml version="1.0" encoding="UTF-8"?>

<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.0.xsd">

<!-- linkgroup.freespaceinbytes only ever decreases in trigger updates below; this is a heuristic
to quickly update freespaceinbytes as space is consumed. The real value is provided by
periodic updates from pool manager. The heuristic does not increase linkgroup.freespaceinbytes
as that would introduce a risk of advertising more free space than is actually available. -->

<changeSet id="1" author="behrmann" dbms="hsqldb" runOnChange="true">
<comment>Create srmlinkgroup trigger to prevent over allocating link groups</comment>
<sql>DROP TRIGGER tgr_srmlinkgroup_update IF EXISTS</sql>
<createProcedure>
CREATE TRIGGER tgr_srmlinkgroup_update BEFORE UPDATE ON srmlinkgroup
REFERENCING OLD ROW AS old NEW ROW AS new
FOR EACH ROW WHEN (new.reservedspaceinbytes > old.reservedspaceinbytes AND new.reservedspaceinbytes > new.freespaceinbytes)
BEGIN ATOMIC
SIGNAL SQLSTATE '23D01' SET MESSAGE_TEXT = 'Not enough free space in link group ';
END;
</createProcedure>
</changeSet>

<changeSet id="2" author="behrmann" dbms="hsqldb" runOnChange="true">
<comment>Create srmspace triggers for maintaining accumulated fields</comment>
<sql>DROP TRIGGER tgr_srmspace_insert IF EXISTS</sql>
<createProcedure>
CREATE TRIGGER tgr_srmspace_insert AFTER INSERT ON srmspace
REFERENCING NEW ROW AS space
FOR EACH ROW WHEN (space.state = 0)
UPDATE srmlinkgroup
SET reservedspaceinbytes = reservedspaceinbytes + space.sizeinbytes - space.usedspaceinbytes,
freespaceinbytes = GREATEST(freespaceinbytes - space.usedspaceinbytes, 0)
WHERE id = space.linkGroupId;
</createProcedure>

<sql>DROP TRIGGER tgr_srmspace_delete IF EXISTS</sql>
<createProcedure>
CREATE TRIGGER tgr_srmspace_delete AFTER DELETE ON srmspace
REFERENCING OLD ROW AS space
FOR EACH ROW WHEN (space.state = 0)
UPDATE srmlinkgroup SET reservedspaceinbytes = reservedspaceinbytes - space.sizeinbytes + space.usedspaceinbytes WHERE id = space.linkgroupid;
</createProcedure>

<sql>DROP TRIGGER tgr_srmspace_update IF EXISTS</sql>
<createProcedure>
CREATE TRIGGER tgr_srmspace_update AFTER UPDATE ON srmspace
REFERENCING OLD ROW AS old NEW ROW AS new
FOR EACH ROW
BEGIN ATOMIC
IF old.state = 0 AND new.state = 0 THEN
IF old.linkGroupId != new.linkGroupId THEN
UPDATE srmlinkgroup
SET reservedspaceinbytes = reservedspaceinbytes - old.sizeinbytes + old.usedspaceinbytes
WHERE id = old.linkgroupid;
UPDATE srmlinkgroup
SET reservedspaceinbytes = reservedspaceinbytes + new.sizeinbytes - new.usedspaceinbytes,
freespaceinbytes = GREATEST(freespaceinbytes - new.usedspaceinbytes, 0)
WHERE id = new.linkgroupid;
ELSEIF old.sizeinbytes &lt;&gt; new.sizeinbytes OR old.usedspaceinbytes &lt;&gt; new.usedspaceinbytes THEN
UPDATE srmlinkgroup
SET reservedspaceinbytes = reservedspaceinbytes - old.sizeinbytes + old.usedspaceinbytes + new.sizeinbytes - new.usedspaceinbytes,
freespaceinbytes = GREATEST(LEAST(freespaceinbytes, freespaceinbytes - new.usedspaceinbytes + old.usedspaceinbytes), 0)
WHERE id = old.linkgroupid;
END IF;
ELSEIF old.state = 0 AND new.state &lt;&gt; 0 THEN
UPDATE srmlinkgroup SET reservedspaceinbytes = reservedspaceinbytes - old.sizeinBytes + old.usedspaceinbytes WHERE id = old.linkgroupid;
ELSEIF old.state &lt;&gt; 0 AND new.state = 0 THEN
UPDATE srmlinkgroup
SET reservedspaceinbytes = reservedspaceinbytes + new.sizeinbytes - new.usedspaceinbytes,
freespaceinbytes = GREATEST(freespaceinbytes - new.usedspaceinbytes, 0)
WHERE id = new.linkgroupid;
END IF;
END;
</createProcedure>

<rollback>
<sql>DROP TRIGGER tgr_srmspace_insert IF EXISTS</sql>
<sql>DROP TRIGGER tgr_srmspace_update IF EXISTS</sql>
<sql>DROP TRIGGER tgr_srmspace_delete IF EXISTS</sql>
</rollback>
</changeSet>

<changeSet id="3" author="behrmann" dbms="hsqldb" runOnChange="true">
<!-- Comment taken from old Java code: Idea below is questionable. We resize space reservation
to fit this file. This way we attempt to guarantee that there is no negative numbers in
LinkGroup. -->
<comment>Create srmspace trigger to enlarge space to fit its files</comment>
<sql>DROP TRIGGER tgr_srmspace_increase_size IF EXISTS</sql>
<createProcedure>
CREATE TRIGGER tgr_srmspace_increase_size BEFORE UPDATE ON srmspace
REFERENCING OLD ROW AS old NEW ROW as new
FOR EACH ROW WHEN (new.allocatedspaceinbytes + new.usedspaceinbytes > new.sizeinbytes)
SET new.sizeinbytes = new.allocatedspaceinbytes + new.usedspaceinbytes;
</createProcedure>
<rollback>
<sql>DROP TRIGGER tgr_srmspace_increase_size IF EXISTS</sql>
</rollback>
</changeSet>

<changeSet id="4" author="behrmann" dbms="hsqldb" runOnChange="true">
<comment>Create srmspacefile triggers for maintaining accumulated fields</comment>
<sql>DROP TRIGGER tgr_srmspacefile_insert IF EXISTS</sql>
<createProcedure>
CREATE TRIGGER tgr_srmspacefile_insert AFTER INSERT ON srmspacefile
REFERENCING NEW ROW AS new
FOR EACH ROW
BEGIN ATOMIC
CASE new.state
WHEN 0, 1 THEN
UPDATE srmspace SET allocatedspaceinbytes = allocatedspaceinbytes + new.sizeinbytes WHERE id = new.spacereservationid;
WHEN 2 THEN
UPDATE srmspace SET usedspaceinbytes = usedspaceinbytes + new.sizeinbytes WHERE id = new.spacereservationid;
END CASE;
END;
</createProcedure>

<sql>DROP TRIGGER tgr_srmspacefile_update IF EXISTS</sql>
<createProcedure>
CREATE TRIGGER tgr_srmspacefile_decrement_allocated AFTER UPDATE ON srmspacefile
REFERENCING OLD ROW AS old NEW ROW AS new
FOR EACH ROW
BEGIN ATOMIC
DECLARE allocatedDelta BIGINT;
DECLARE usedDelta BIGINT;
IF old.spaceReservationId = new.spaceReservationId THEN
SET allocatedDelta =
CASE WHEN new.state IN (0, 1) THEN new.sizeinbytes ELSE 0 END
-
CASE WHEN old.state IN (0, 1) THEN old.sizeinbytes ELSE 0 END;
SET usedDelta =
CASE WHEN new.state = 2 THEN new.sizeinbytes ELSE 0 END
-
CASE WHEN old.state = 2 THEN old.sizeinbytes ELSE 0 END;
IF allocatedDelta &lt;&gt; 0 OR usedDelta &lt;&gt; 0 THEN
UPDATE srmspace
SET allocatedspaceinbytes = allocatedspaceinbytes + allocatedDelta,
usedspaceinbytes = usedspaceinbytes + usedDelta
WHERE id = old.spaceReservationId;
END IF;
ELSE
CASE old.state
WHEN 0, 1 THEN
UPDATE srmspace SET allocatedspaceinbytes = allocatedspaceinbytes - old.sizeinbytes WHERE id = old.spacereservationid;
WHEN 2 THEN
UPDATE srmspace SET usedspaceinbytes = usedspaceinbytes - old.sizeinbytes WHERE id = old.spacereservationid;
END CASE;
CASE new.state
WHEN 0, 1 THEN
UPDATE srmspace SET allocatedspaceinbytes = allocatedspaceinbytes + new.sizeinbytes WHERE id = new.spacereservationid;
WHEN 2 THEN
UPDATE srmspace SET usedspaceinbytes = usedspaceinbytes + new.sizeinbytes WHERE id = new.spacereservationid;
END CASE;
END IF;
END;
</createProcedure>

<sql>DROP TRIGGER tgr_srmspacefile_delete IF EXISTS</sql>
<createProcedure>
CREATE TRIGGER tgr_srmspacefile_delete AFTER DELETE ON srmspacefile
REFERENCING OLD ROW AS old
FOR EACH ROW
BEGIN ATOMIC
CASE old.state
WHEN 0, 1 THEN
UPDATE srmspace SET allocatedspaceinbytes = allocatedspaceinbytes - old.sizeinbytes WHERE id = old.spacereservationid;
WHEN 2 THEN
UPDATE srmspace SET usedspaceinbytes = usedspaceinbytes - old.sizeinbytes WHERE id = old.spacereservationid;
END CASE;
END;
</createProcedure>

<rollback>
<sql>DROP TRIGGER tgr_srmspacefile_insert IF EXISTS</sql>
<sql>DROP TRIGGER tgr_srmspacefile_update IF EXISTS</sql>
<sql>DROP TRIGGER tgr_srmspacefile_delete IF EXISTS</sql>
</rollback>
</changeSet>
</databaseChangeLog>

0 comments on commit 222cae0

Please sign in to comment.