Splitting the queries allows for significant perfomance boost.
Also tidied up the schemas to be consistent on providing a default value
for NOT NULL columns and not allow expiry_time to be NULL, simplifying
the queries chosing expired addresses.
SELECT TOP(1) FramedIPAddress
FROM radippool
WHERE pool_name = @v_pool_name
- AND ( expiry_time < CURRENT_TIMESTAMP OR expiry_time IS NULL )
+ AND expiry_time < CURRENT_TIMESTAMP
ORDER BY
expiry_time
)
#
# $Id$
-# MSSQL-specific syntax
-allocate_begin = "BEGIN TRAN"
-allocate_commit = "COMMIT TRAN"
+# MSSQL-specific syntax - only needed if the queries need wrapping as
+# a transaction - specifically when the SELECT and UPDATE are separate queries
+#allocate_begin = "BEGIN TRAN"
+#allocate_commit = "COMMIT TRAN"
#
-# The ORDER BY clause of this query tries to allocate the same IP-address
-# which user had last session...
+# This query tries to allocate the same IP-address to the user
+# that they had last session
+#
+allocate_existing = "\
+ WITH cte AS ( \
+ SELECT TOP(1) \
+ FramedIPAddress, NASIPAddress, pool_key, CallingStationId, UserName, expiry_time \
+ FROM ${ippool_table} WITH (xlock rowlock readpast) \
+ WHERE pool_name = '%{control:${pool_name}}' \
+ AND NASIPAddress = '%{NAS-IP-Address}' \
+ AND pool_key = '${pool_key}' \
+ ORDER BY expiry_time DESC \
+ ) \
+ UPDATE cte \
+ SET \
+ CallingStationId = '%{Calling-Station-Id}', \
+ UserName = '%{User-Name}', \
+ expiry_time = DATEADD(SECOND,${lease_duration},CURRENT_TIMESTAMP) \
+ OUTPUT INSERTED.FramedIPAddress \
+ FROM ${ippool_table}"
+
+#
+# If no address was returned by the above query, use the following
+# to find a free one in the pool
#
allocate_find = "\
WITH cte AS ( \
- SELECT TOP(1) FramedIPAddress FROM ${ippool_table} \
+ SELECT TOP(1) \
+ FramedIPAddress, NASIPAddress, pool_key, CallingStationId, UserName, expiry_time \
+ FROM ${ippool_table} WITH (xlock rowlock readpast) \
WHERE pool_name = '%{control:${pool_name}}' \
- AND ( expiry_time < CURRENT_TIMESTAMP OR expiry_time IS NULL ) \
- OR ( NASIPAddress = '%{NAS-IP-Address}' AND pool_key = '${pool_key}' ) \
- ORDER BY \
- CASE WHEN UserName = '%{User-Name}' THEN 0 ELSE 1 END, \
- CASE WHEN CallingStationId = '%{Calling-Station-Id}' THEN 0 ELSE 1 END, \
- expiry_time \
+ AND expiry_time < CURRENT_TIMESTAMP \
+ ORDER BY expiry_time \
) \
- UPDATE cte WITH (rowlock, readpast) \
- SET FramedIPAddress = FramedIPAddress \
- OUTPUT INSERTED.FramedIPAddress"
+ UPDATE cte \
+ SET \
+ NASIPAddress = '%{NAS-IP-Address}', \
+ pool_key = '${pool_key}', \
+ CallingStationId = '%{Calling-Station-Id}', \
+ UserName = '%{User-Name}', \
+ expiry_time = DATEADD(SECOND,${lease_duration},CURRENT_TIMESTAMP) \
+ OUTPUT INSERTED.FramedIPAddress \
+ FROM ${ippool_table}"
#
# If you prefer to allocate a random IP address every time, use this query instead.
-# Note: This is very slow if you have a lot of free IPs.
+# Note: This is very slow if you have a lot of free IPs. This query doesn't update
+# the pool so a separate allocate_update will be required, as will the allocate_begin
+# and allocate_commit transaction wrappers.
#
#allocate_find = "\
# WITH cte AS ( \
# SELECT TOP(1) FramedIPAddress FROM ${ippool_table} \
# WHERE pool_name = '%{control:${pool_name}}' \
-# AND ( \
-# expiry_time < CURRENT_TIMESTAMP OR expiry_time IS NULL \
-# ) \
+# AND expiry_time < CURRENT_TIMESTAMP \
# ORDER BY \
# newid() \
# ) \
#
# This is the final IP Allocation query, which saves the allocated ip details.
#
-allocate_update = "\
- UPDATE ${ippool_table} \
- SET \
- NASIPAddress = '%{NAS-IP-Address}', pool_key = '${pool_key}', \
- CallingStationId = '%{Calling-Station-Id}', \
- UserName = '%{User-Name}', expiry_time = DATEADD(SECOND,${lease_duration},CURRENT_TIMESTAMP) \
- WHERE FramedIPAddress = '%I'"
+#allocate_update = "\
+# UPDATE ${ippool_table} \
+# SET \
+# NASIPAddress = '%{NAS-IP-Address}', pool_key = '${pool_key}', \
+# CallingStationId = '%{Calling-Station-Id}', \
+# UserName = '%{User-Name}', expiry_time = DATEADD(SECOND,${lease_duration},CURRENT_TIMESTAMP) \
+# WHERE FramedIPAddress = '%I'"
#
# Use a stored procedure to find AND allocate the address. Read and customise
UPDATE ${ippool_table} \
SET \
NASIPAddress = '', \
- pool_key = 0, \
+ pool_key = '0', \
CallingStationId = '', \
UserName = '', \
- expiry_time = NULL \
+ expiry_time = CURRENT_TIMESTAMP \
WHERE NASIPAddress = '%{%{Nas-IP-Address}:-%{Nas-IPv6-Address}}' \
AND pool_key = '${pool_key}' \
AND UserName = '%{User-Name}' \
UPDATE ${ippool_table} \
SET \
NASIPAddress = '', \
- pool_key = 0, \
+ pool_key = '0', \
CallingStationId = '', \
UserName = '', \
- expiry_time = NULL \
+ expiry_time = CURRENT_TIMESTAMP \
WHERE NASIPAddress = '%{%{Nas-IP-Address}:-%{Nas-IPv6-Address}}'"
#
UPDATE ${ippool_table} \
SET \
NASIPAddress = '', \
- pool_key = 0, \
+ pool_key = '0', \
CallingStationId = '', \
UserName = '', \
- expiry_time = NULL \
+ expiry_time = CURRENT_TIMESTAMP \
WHERE NASIPAddress = '%{%{Nas-IP-Address}:-%{Nas-IPv6-Address}}'"
pool_name varchar(30) NOT NULL,
FramedIPAddress varchar(15) NOT NULL default '',
NASIPAddress varchar(15) NOT NULL default '',
- CalledStationId VARCHAR(32) NOT NULL,
- CallingStationId VARCHAR(30) NOT NULL,
- expiry_time DATETIME NULL default NULL,
+ CalledStationId VARCHAR(32) NOT NULL default '',
+ CallingStationId VARCHAR(30) NOT NULL default '',
+ expiry_time DATETIME NOT NULL default CURRENT_TIMESTAMP,
UserName varchar(64) NOT NULL default '',
pool_key varchar(30) NOT NULL default '',
PRIMARY KEY (id)
SELECT framedipaddress INTO r_address
FROM radippool
WHERE pool_name = v_pool_name
- AND ( expiry_time < NOW() OR expiry_time IS NULL )
+ AND expiry_time < NOW()
--
-- WHERE ... GET_LOCK(...,0) = 1 is a poor man's SKIP LOCKED that simulates
-- a row-level lock using a "user lock" that allows the locked "rows" to be
-- Here we re-evaluate the original condition for selecting the address
-- to detect a race, in which case we try again...
--
- AND (expiry_time<NOW() OR expiry_time IS NULL);
+ AND expiry_time<NOW();
UNTIL ROW_COUNT() <> 0 END REPEAT;
SELECT framedipaddress INTO r_address
FROM radippool
WHERE pool_name = v_pool_name
- AND ( expiry_time < NOW() OR expiry_time IS NULL )
+ AND expiry_time < NOW()
ORDER BY
expiry_time
LIMIT 1
#skip_locked = "SKIP LOCKED"
#
-# allocate_find obtains a free ip address to satisfy a new request
+# allocate_existing looks up a user's IP-address from their
+# last session.
#
-# The ORDER BY clause of this query tries to allocate the same IP-address
-# that the user had last session:
+allocate_existing = "\
+ SELECT framedipaddress FROM ${ippool_table} \
+ WHERE pool_lane = '%{control:Pool-Name}' \
+ AND nasipaddress = '%{NAS-IP-Address}' \
+ AND pool_key = '${pool_key}' \
+ ORDER BY expiry_time DESC \
+ LIMIT 1 \
+ FOR UPDATE ${skip_locked}"
#
-# username <> User-Name returns 0 on a match and 1 on a mismatch,
-# thus a match sorts first
-# Ths same is true for callingstationid
-# If nothing else, return oldest expiry time
+# If the previous query doesn't find an address then
+# allocate_find obtains a free ip address to satisfy a new request
#
# Limit 1 to ensure only one result is returned
#
allocate_find = "\
SELECT framedipaddress FROM ${ippool_table} \
WHERE pool_name = '%{control:Pool-Name}' \
- AND ( \
- expiry_time < NOW() OR expiry_time IS NULL \
- OR ( nasipaddress = '%{NAS-IP-Address}' AND pool_key = '${pool_key}' ) \
- ) \
- ORDER BY \
- (username <> '%{User-Name}'), \
- (callingstationid <> '%{Calling-Station-Id}'), \
- expiry_time \
+ AND expiry_time < NOW() \
+ ORDER BY expiry_time \
LIMIT 1 \
FOR UPDATE ${skip_locked}"
# `procedure.sql` in this directory to determine the optimal configuration.
#
#allocate_begin = ""
+#allocate_existing = ""
#allocate_find = "\
# CALL fr_allocate_previous_or_new_framedipaddress( \
# '%{control:${pool_name}}', \
# stop_clear = "\
# UPDATE ${ippool_table} \
# SET \
-# expiry_time = 0 \
+# expiry_time = NOW() \
# WHERE nasipaddress = '%{Nas-IP-Address}' \
# AND pool_key = '${pool_key}' \
# AND username = '%{User-Name}' \
UPDATE ${ippool_table} \
SET \
nasipaddress = '', \
- pool_key = 0, \
+ pool_key = '0', \
callingstationid = '', \
username = '', \
- expiry_time = 0 \
+ expiry_time = NOW() \
WHERE nasipaddress = '%{Nas-IP-Address}' \
AND pool_key = '${pool_key}' \
AND username = '%{User-Name}' \
UPDATE ${ippool_table} \
SET \
nasipaddress = '', \
- pool_key = 0, \
+ pool_key = '0', \
callingstationid = '', \
username = '', \
- expiry_time = 0 \
+ expiry_time = NOW() \
WHERE nasipaddress = '%{Nas-IP-Address}'"
#
UPDATE ${ippool_table} \
SET \
nasipaddress = '', \
- pool_key = 0, \
+ pool_key = '0', \
callingstationid = '', \
username = '', \
- expiry_time = 0 \
+ expiry_time = NOW() \
WHERE nasipaddress = '%{Nas-IP-Address}'"
pool_name varchar(30) NOT NULL,
framedipaddress varchar(15) NOT NULL default '',
nasipaddress varchar(15) NOT NULL default '',
- calledstationid VARCHAR(30) NOT NULL,
- callingstationid VARCHAR(30) NOT NULL,
- expiry_time DATETIME NOT NULL default 0,
+ calledstationid VARCHAR(30) NOT NULL default '',
+ callingstationid VARCHAR(30) NOT NULL default '',
+ expiry_time DATETIME NOT NULL default NOW(),
username varchar(64) NOT NULL default '',
- pool_key varchar(30) NOT NULL,
+ pool_key varchar(30) NOT NULL default '',
PRIMARY KEY (id),
KEY radippool_poolname_expire (pool_name, expiry_time),
KEY framedipaddress (framedipaddress),
+CREATE SEQUENCE radippool_seq START WITH 1 INCREMENT BY 1;
+
CREATE TABLE radippool (
- id INT PRIMARY KEY,
+ id INT DEFAULT ON NULL radippool_seq.NEXTVAL PRIMARY KEY,
pool_name VARCHAR(30) NOT NULL,
framedipaddress VARCHAR(15) NOT NULL,
- nasipaddress VARCHAR(15) NOT NULL,
- pool_key VARCHAR(30) NOT NULL,
- CalledStationId VARCHAR(64) NOT NULL,
- CallingStationId VARCHAR(64) NOT NULL,
- expiry_time timestamp(0) NOT NULL,
+ nasipaddress VARCHAR(15) DEFAULT '',
+ pool_key VARCHAR(30) DEFAULT '',
+ CalledStationId VARCHAR(64) DEFAULT '',
+ CallingStationId VARCHAR(64) DEFAULT '',
+ expiry_time timestamp(0) DEFAULT CURRENT_TIMESTAMP,
username VARCHAR(64)
);
CREATE INDEX radippool_framedipaddress ON radippool (framedipaddress);
CREATE INDEX radippool_nasip_poolkey_ipaddress ON radippool (nasipaddress, pool_key, framedipaddress);
-CREATE SEQUENCE radippool_seq START WITH 1 INCREMENT BY 1;
-
-CREATE OR REPLACE TRIGGER radippool_serialnumber
- BEFORE INSERT OR UPDATE OF id ON radippool
- FOR EACH ROW
- BEGIN
- if ( :new.id = 0 or :new.id is null ) then
- SELECT radippool_seq.nextval into :new.id from dual;
- end if;
- END;
-/
# Using SKIP LOCKED speed up the allocate_find query by 10
# times. However, it requires PostgreSQL >= 9.5.
#
-# Uncomment the next line to automatically use SKIP LOCKED
-#skip_locked = "SKIP LOCKED"
+# If you are using an older version of PostgreSQL comment out the following:
+skip_locked = "SKIP LOCKED"
#
-# This query allocates an IP address from the Pool
-# The ORDER BY clause of this query tries to allocate the same IP-address
-# to the user that they had last session...
+# This query tries to allocate the same IP-address to the user
+# that they had last session
+#
+allocate_existing "\
+ WITH cte AS ( \
+ SELECT framedipaddress \
+ FROM ${ippool_table} \
+ WHERE pool_name = '%{control:Pool-Name}' \
+ AND nasipaddress = '%{NAS-IP-Address}' \
+ AND pool_key = '${pool_key}' \
+ LIMIT 1 \
+ FOR UPDATE ${skip_locked} \
+ ) \
+ UPDATE ${ippool_table} \
+ SET \
+ nasipaddress = '%{NAS-IP-Address}', \
+ pool_key = '${pool_key}', \
+ callingstationid = '%{Calling-Station-Id}', \
+ username = '%{SQL-User-Name}', \
+ expiry_time = 'now'::timestamp(0) + '${lease_duration} second'::interval \
+ FROM cte \
+ WHERE ${ippool_table}.framedipaddress = cte.framedipaddress \
+ RETURNING cte.framedipaddress"
+
+#
+# If no address was returned by the above query, use the following
+# to find a free one in the pool
#
allocate_find = "\
- SELECT framedipaddress \
- FROM ${ippool_table} \
- WHERE pool_name = '%{control:Pool-Name}' \
- AND ( \
- expiry_time < 'now'::timestamp(0) \
- OR ( nasipaddress = '%{NAS-IP-Address}' AND pool_key = '${pool_key}' ) \
+ WITH cte AS ( \
+ SELECT framedipaddress \
+ FROM ${ippool_table} \
+ WHERE pool_name = '%{control:Pool-Name}' \
+ AND expiry_time < 'now'::timestamp(0) \
+ ORDER BY expiry_time \
+ LIMIT 1 \
+ FOR UPDATE ${skip_locked} \
) \
- ORDER BY \
- (username <> '%{SQL-User-Name}'), \
- (callingstationid <> '%{Calling-Station-Id}'), \
- expiry_time \
- LIMIT 1 \
- FOR UPDATE ${skip_locked}"
+ UPDATE ${ippool_table} \
+ SET \
+ nasipaddress = '%{NAS-IP-Address}', \
+ pool_key = '${pool_key}', \
+ callingstationid = '%{Calling-Station-Id}', \
+ username = '%{SQL-User-Name}', \
+ expiry_time = 'now'::timestamp(0) + '${lease_duration} second'::interval \
+ FROM cte \
+ WHERE ${ippool_table}.framedipaddress = cte.framedipaddress \
+ RETURNING cte.framedipaddress"
+
+#
+# Using the two queries above, the following can be blank since they
+# do not need transactions and the update is done within the same query
+#
+
+allocate_begin = ""
+allocate_update = ""
+allocate_commit = ""
#
# If you prefer to allocate a random IP address every time, use this query instead
#
# This query marks the IP address handed out by "allocate-find" as used
# for the period of "lease_duration" after which time it may be reused.
-#
-allocate_update = "\
- UPDATE ${ippool_table} \
- SET \
- nasipaddress = '%{NAS-IP-Address}', \
- pool_key = '${pool_key}', \
- callingstationid = '%{Calling-Station-Id}', \
- username = '%{SQL-User-Name}', \
- expiry_time = 'now'::timestamp(0) + '${lease_duration} second'::interval \
- WHERE framedipaddress = '%I'"
+# It is only needed if the update of the record is not done within the
+# query that selects the address.
+#
+#allocate_update = "\
+# UPDATE ${ippool_table} \
+# SET \
+# nasipaddress = '%{NAS-IP-Address}', \
+# pool_key = '${pool_key}', \
+# callingstationid = '%{Calling-Station-Id}', \
+# username = '%{SQL-User-Name}', \
+# expiry_time = 'now'::timestamp(0) + '${lease_duration} second'::interval \
+# WHERE framedipaddress = '%I'"
#
# Use a stored procedure to find AND allocate the address. Read and customise
UPDATE ${ippool_table} \
SET \
nasipaddress = '', \
- pool_key = 0, \
+ pool_key = '0', \
callingstationid = '', \
expiry_time = 'now'::timestamp(0) - '1 second'::interval \
WHERE nasipaddress = '%{Nas-IP-Address}' \
UPDATE ${ippool_table} \
SET \
nasipaddress = '', \
- pool_key = 0, \
+ pool_key = '0', \
callingstationid = '', \
expiry_time = 'now'::timestamp(0) - '1 second'::interval \
WHERE nasipaddress = '%{Nas-IP-Address}'"
UPDATE ${ippool_table} \
SET \
nasipaddress = '', \
- pool_key = 0, \
+ pool_key = '0', \
callingstationid = '', \
expiry_time = 'now'::timestamp(0) - '1 second'::interval \
WHERE nasipaddress = '%{Nas-IP-Address}'"
pool_name varchar(64) NOT NULL,
FramedIPAddress INET NOT NULL,
NASIPAddress VARCHAR(16) NOT NULL default '',
- pool_key VARCHAR(64) NOT NULL default 0,
- CalledStationId VARCHAR(64),
+ pool_key VARCHAR(64) NOT NULL default '0',
+ CalledStationId VARCHAR(64) NOT NULL default '',
CallingStationId text NOT NULL default ''::text,
- expiry_time TIMESTAMP(0) without time zone NOT NULL default 'now'::timestamp(0),
- username text DEFAULT ''::text
+ expiry_time TIMESTAMP(0) without time zone NOT NULL default NOW(),
+ username text NOT NULL DEFAULT ''::text
);
CREATE INDEX radippool_poolname_expire ON radippool USING btree (pool_name, expiry_time);
allocate_commit = "COMMIT"
#
-# The ORDER BY clause of this query tries to allocate the same IP-address
-# which user had last session...
+# allocate_exsiting looks for a user's IP-Address from their last session
+#
+allocate_existing = "\
+ SELECT framedipaddress \
+ FROM ${ippool_table} \
+ WHERE pool_name = '%{control:${pool_name}}' \
+ AND nasipaddress = '%{NAS-IP-Address}' \
+ AND pool_key = '${pool_key}' \
+ ORDER BY expiry_time DESC \
+ LIMIT 1"
+
+#
+# If the previous query does not return an address then
+# allocate_find will find a free address from the pool
#
allocate_find = "\
SELECT framedipaddress \
FROM ${ippool_table} \
WHERE pool_name = '%{control:${pool_name}}' \
- AND ( \
- ( expiry_time < datetime('now') OR expiry_time IS NULL ) \
- OR ( nasipaddress = '%{NAS-IP-Address}' AND pool_key = '${pool_key}' ) \
- ) \
- ORDER BY \
- (username <> '%{User-Name}'), \
- (callingstationid <> '%{Calling-Station-Id}'), \
- expiry_time \
+ expiry_time < datetime('now') \
+ ORDER BY expiry_time \
LIMIT 1"
#
# SELECT framedipaddress \
# FROM ${ippool_table} \
# WHERE pool_name = '%{control:${pool_name}}' \
-# AND expiry_time IS NULL \
+# AND expiry_time < datetime('now') \
# ORDER BY RAND() \
# LIMIT 1"
UPDATE ${ippool_table} \
SET \
nasipaddress = '', \
- pool_key = 0, \
+ pool_key = '0', \
callingstationid = '', \
username = '', \
- expiry_time = NULL \
+ expiry_time = datetime('now') \
WHERE nasipaddress = '%{%{Nas-IP-Address}:-%{Nas-IPv6-Address}}' \
AND pool_key = '${pool_key}' \
AND username = '%{User-Name}' \
UPDATE ${ippool_table} \
SET \
nasipaddress = '', \
- pool_key = 0, \
+ pool_key = '0', \
callingstationid = '', \
username = '', \
- expiry_time = NULL \
+ expiry_time = datetime('now') \
WHERE nasipaddress = '%{%{Nas-IP-Address}:-%{Nas-IPv6-Address}}'"
#
UPDATE ${ippool_table} \
SET \
nasipaddress = '', \
- pool_key = 0, \
+ pool_key = '0', \
callingstationid = '', \
username = '', \
- expiry_time = NULL \
+ expiry_time = datetime('now') \
WHERE nasipaddress = '%{%{Nas-IP-Address}:-%{Nas-IPv6-Address}}'"
pool_name varchar(30) NOT NULL,
framedipaddress varchar(15) NOT NULL default '',
nasipaddress varchar(15) NOT NULL default '',
- calledstationid VARCHAR(30) NOT NULL,
- callingstationid VARCHAR(30) NOT NULL,
- expiry_time DATETIME NULL default NULL,
+ calledstationid VARCHAR(30) NOT NULL default '',
+ callingstationid VARCHAR(30) NOT NULL default '',
+ expiry_time DATETIME NOT NULL default (DATETIME('now')),
username varchar(64) NOT NULL default '',
- pool_key varchar(30) NOT NULL
+ pool_key varchar(30) NOT NULL default ''
);
CREATE INDEX radippool_poolname_expire ON radippool(pool_name, expiry_time);