Use table cache_waypoint_pool to generate a list of unused waypoints and assign waypoints to new caches from this list.
This commit is contained in:
@@ -316,7 +316,24 @@
|
||||
*/
|
||||
$opt['logic']['ocprefixes'] = 'oc';
|
||||
|
||||
/* Database charset
|
||||
/* pregenerated waypoint list for new caches
|
||||
* - Waypoint prefix (OC, OP, OZ ... AA=local development)
|
||||
* - When pool contains less than min_count, generation process starts
|
||||
* and fills up the pool until max_count is reached.
|
||||
*/
|
||||
$opt['logic']['waypoint_pool']['prefix'] = 'AA';
|
||||
$opt['logic']['waypoint_pool']['min_count'] = 1000;
|
||||
$opt['logic']['waypoint_pool']['max_count'] = 2000;
|
||||
// chars used for waypoints. Remember to reinstall triggers and clear cache_waypoint_pool after changing
|
||||
$opt['logic']['waypoint_pool']['valid_chars'] = '0123456789ABCDEF';
|
||||
// fill_gaps = true: search for gaps between used waypoints and fill up these gaps
|
||||
// (fill_gaps is slow and CPU intensive on database server. For
|
||||
// productive servers you may want to generate some waypoints
|
||||
// without fill_gaps first)
|
||||
// fill_gaps = false: continue with the last waypoint
|
||||
$opt['logic']['waypoint_pool']['fill_gaps'] = false;
|
||||
|
||||
/* Database charset
|
||||
* frontend and php charsets are UTF-8
|
||||
* here you can set a different charset for the MySQL-Engine
|
||||
* usefull if your database is not UTF-8.
|
||||
|
||||
@@ -75,6 +75,99 @@
|
||||
END IF;
|
||||
END;");
|
||||
|
||||
// get decimal value of waypoint
|
||||
sql_dropFunction('WPTODEC');
|
||||
sql("CREATE FUNCTION `WPTODEC` (wp VARCHAR(7), prefix VARCHAR(2)) RETURNS INT DETERMINISTIC SQL SECURITY INVOKER
|
||||
BEGIN
|
||||
-- all used chars in waypoint, in their ascending order
|
||||
DECLARE WP_ORDER CHAR(36) DEFAULT '&1';
|
||||
-- list of base 36 chars in their ascending order
|
||||
DECLARE B36_ORDER CHAR(36) DEFAULT '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||
-- will contain the waypoint value, without prefix
|
||||
DECLARE WP_VALUE CHAR(5) DEFAULT '00000';
|
||||
-- will contain WP_VALUE where all chars replaced by their equivalents in B36_ORDER
|
||||
DECLARE B36_VALUE CHAR(5) DEFAULT '';
|
||||
-- loop counter
|
||||
DECLARE WP_POS INT DEFAULT 1;
|
||||
-- index of a char in WP_ORDER/B36_ORDER
|
||||
DECLARE WP_ORDER_INDEX INT;
|
||||
|
||||
-- validate input
|
||||
IF ISNULL(wp) OR ISNULL(prefix) THEN
|
||||
RETURN 0;
|
||||
END IF;
|
||||
IF LENGTH(prefix) != 2 OR LENGTH(wp)<3 OR LENGTH(wp)>7 THEN
|
||||
RETURN 0;
|
||||
END IF;
|
||||
IF LEFT(wp, 2) != prefix THEN
|
||||
RETURN 0;
|
||||
END IF;
|
||||
|
||||
-- get waypoint value with exactly 5 digits
|
||||
SET WP_VALUE = RIGHT(CONCAT('00000', SUBSTRING(wp, 3)), 5);
|
||||
|
||||
-- replace each char in WP_VALUE with the equivalent base 36 char
|
||||
REPEAT
|
||||
SET WP_ORDER_INDEX = LOCATE(SUBSTRING(WP_VALUE, WP_POS, 1), WP_ORDER);
|
||||
IF WP_ORDER_INDEX = 0 THEN
|
||||
RETURN 0;
|
||||
END IF;
|
||||
SET B36_VALUE = CONCAT(B36_VALUE, SUBSTRING(B36_ORDER, WP_ORDER_INDEX, 1));
|
||||
SET WP_POS = WP_POS + 1;
|
||||
UNTIL WP_POS>5 END REPEAT;
|
||||
|
||||
-- now use CONV() to convert from base 36 system to decimal
|
||||
RETURN CONV(B36_VALUE, LENGTH(WP_ORDER), 10);
|
||||
|
||||
END;",
|
||||
$opt['logic']['waypoint_pool']['valid_chars']);
|
||||
|
||||
// inverse function of WPTODEC
|
||||
sql_dropFunction('DECTOWP');
|
||||
sql("CREATE FUNCTION `DECTOWP` (wp INT, prefix VARCHAR(2)) RETURNS VARCHAR(7) DETERMINISTIC SQL SECURITY INVOKER
|
||||
BEGIN
|
||||
-- all used chars in waypoint, in their ascending order
|
||||
DECLARE WP_ORDER CHAR(36) DEFAULT '&1';
|
||||
-- list of base 36 chars in their ascending order
|
||||
DECLARE B36_ORDER CHAR(36) DEFAULT '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||
-- base 36 value of the decimal waypoint value
|
||||
DECLARE B36_VALUE VARCHAR(5);
|
||||
-- will contain the waypoint value, without prefix
|
||||
DECLARE WP_VALUE CHAR(5) DEFAULT '';
|
||||
-- loop counter
|
||||
DECLARE B36_POS INT DEFAULT 1;
|
||||
-- index of a char in WP_ORDER/B36_ORDER
|
||||
DECLARE B36_ORDER_INDEX INT;
|
||||
|
||||
-- validate input
|
||||
IF ISNULL(wp) OR ISNULL(prefix) THEN
|
||||
RETURN '';
|
||||
END IF;
|
||||
IF LENGTH(prefix) != 2 OR wp=0 THEN
|
||||
RETURN '';
|
||||
END IF;
|
||||
|
||||
-- convert the decimal waypoint value to base 36
|
||||
SET B36_VALUE = CONV(wp, 10, LENGTH(WP_ORDER));
|
||||
|
||||
-- replace each char in B36_VALUE with the equivalent wp-char
|
||||
REPEAT
|
||||
SET B36_ORDER_INDEX = LOCATE(SUBSTRING(B36_VALUE, B36_POS, 1), B36_ORDER);
|
||||
IF B36_ORDER_INDEX = 0 THEN
|
||||
RETURN '';
|
||||
END IF;
|
||||
SET WP_VALUE = CONCAT(WP_VALUE, SUBSTRING(WP_ORDER, B36_ORDER_INDEX, 1));
|
||||
SET B36_POS = B36_POS + 1;
|
||||
UNTIL B36_POS>LENGTH(B36_VALUE) END REPEAT;
|
||||
|
||||
IF LENGTH(WP_VALUE)<4 THEN
|
||||
RETURN CONCAT(prefix, RIGHT(CONCAT('0000', WP_VALUE), 4));
|
||||
ELSE
|
||||
RETURN CONCAT(prefix, WP_VALUE);
|
||||
END IF;
|
||||
END;",
|
||||
$opt['logic']['waypoint_pool']['valid_chars']);
|
||||
|
||||
/* Stored procedures containing database logic
|
||||
*/
|
||||
|
||||
|
||||
8
htdocs/doc/sql/tables/cache_waypoint_pool.sql
Normal file
8
htdocs/doc/sql/tables/cache_waypoint_pool.sql
Normal file
@@ -0,0 +1,8 @@
|
||||
SET NAMES 'utf8';
|
||||
DROP TABLE IF EXISTS `cache_waypoint_pool`;
|
||||
CREATE TABLE `cache_waypoint_pool` (
|
||||
`wp_oc` char(7) NOT NULL,
|
||||
`cache_id` int(10) unsigned default NULL,
|
||||
PRIMARY KEY (`wp_oc`),
|
||||
KEY `cache_id` (`cache_id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ;
|
||||
@@ -86,43 +86,26 @@
|
||||
// set a unique waypoint to this cache
|
||||
function setCacheWaypoint($cacheid)
|
||||
{
|
||||
global $oc_waypoint_prefix;
|
||||
global $opt;
|
||||
|
||||
// The following code runs into trouble, if multiple users/threads request a new
|
||||
// waypoint synchronously (-> RT ticket #4071). We will hack around this problem by
|
||||
// repeating the operation with random delays. Another solution would be a table-lock.
|
||||
// cleanup previous assignments failures
|
||||
sql("DELETE FROM `cache_waypoint_pool` WHERE `cache_id`='&1'", $cacheid);
|
||||
|
||||
// 2012-08-23 following
|
||||
// changes: removed 4 hexdigits limit; added random delay;
|
||||
// increased maxloop 10 -> 20; simplified loop
|
||||
// reserve a waypoint
|
||||
sql("UPDATE `cache_waypoint_pool` SET `cache_id`='&1' ORDER BY WPTODEC(`wp_oc`, '&2') ASC LIMIT 1", $cacheid, $opt['logic']['waypoint_pool']['prefix']);
|
||||
|
||||
$nLoop = 20;
|
||||
// TODO: cronjob for waypoint pool generation may not run on development systems
|
||||
// add a fix to generate a new waypoints on demand (insert this new waypoint to cache_waypoint_pool with reserved cache_id
|
||||
// and follow standard assignment code to prevent race conditions with cronjob)
|
||||
|
||||
do
|
||||
{
|
||||
// add zero to convert CONV's string result to a sortable number
|
||||
$rs = sql("SELECT MAX(0 + CONV(SUBSTR(wp_oc,3),16,10)) maxwp FROM `caches` WHERE wp_oc!='OCGC77'");
|
||||
$r = sql_fetch_assoc($rs);
|
||||
mysql_free_result($rs);
|
||||
// assign reserved waypoint to the cache
|
||||
// for the moment, we use IGNORE to catch duplicate keys that occur in any failure case
|
||||
// the cache keeps without a waypoint in this case. Later we change field caches.wp_oc to NOT NULL and assign waypoint in BEFORE INSERT trigger
|
||||
sql("UPDATE IGNORE `caches` INNER JOIN `cache_waypoint_pool` ON `caches`.`cache_id`=`cache_waypoint_pool`.`cache_id` SET `caches`.`wp_oc`=`cache_waypoint_pool`.`wp_oc` WHERE `caches`.`cache_id`='&1'", $cacheid);
|
||||
|
||||
if ($r['maxwp'] == null)
|
||||
$nNext = 1; // first cache in database
|
||||
else
|
||||
$nNext = $r['maxwp'] + 1;
|
||||
|
||||
$nNext = dechex($nNext);
|
||||
while (mb_strlen($nNext) < 4)
|
||||
$nNext = '0' . $nNext;
|
||||
|
||||
$sWP = $oc_waypoint_prefix . mb_strtoupper($nNext);
|
||||
|
||||
if (sql("UPDATE IGNORE `caches` SET `wp_oc`='&1' WHERE `cache_id`='&2' AND ISNULL(`wp_oc`)", $sWP, $cacheid))
|
||||
$nLoop = 0;
|
||||
else
|
||||
usleep(rand(0,50000));
|
||||
|
||||
} while (--$nLoop > 0);
|
||||
}
|
||||
// cleanup
|
||||
sql("DELETE FROM `cache_waypoint_pool` WHERE `cache_id`='&1'", $cacheid);
|
||||
}
|
||||
|
||||
function setLastFound($cacheid)
|
||||
{
|
||||
|
||||
@@ -40,10 +40,6 @@
|
||||
$oc_nodeid = 4;
|
||||
$opt['logic']['node']['id'] = 4;
|
||||
|
||||
// waypoint prefix of the node
|
||||
// OC = oc.de, OP = oc.pl, ... AA = local development
|
||||
$oc_waypoint_prefix = 'OC';
|
||||
|
||||
//name of the cookie
|
||||
$opt['cookie']['name'] = 'oc_devel';
|
||||
$opt['cookie']['path'] = '/';
|
||||
@@ -120,7 +116,25 @@
|
||||
|
||||
$opt['translate']['debug'] = false;
|
||||
|
||||
// see config2/settings-dist.inc.php
|
||||
// copy of config2/settings-dist.inc.php
|
||||
/* pregenerated waypoint list for new caches
|
||||
* - Waypoint prefix (OC, OP, OZ etc.)
|
||||
* - When pool contains less than min_count, generation process starts
|
||||
* and fills up the pool until max_count is reached.
|
||||
*/
|
||||
$opt['logic']['waypoint_pool']['prefix'] = 'AA';
|
||||
$opt['logic']['waypoint_pool']['min_count'] = 1000;
|
||||
$opt['logic']['waypoint_pool']['max_count'] = 2000;
|
||||
// chars used for waypoints. Remember to reinstall triggers and clear cache_waypoint_pool after changing
|
||||
$opt['logic']['waypoint_pool']['valid_chars'] = '0123456789ABCDEF';
|
||||
// fill_gaps = true: search for gaps between used waypoints and fill up these gaps
|
||||
// (fill_gaps is slow and CPU intensive on database server. For
|
||||
// productive servers you may want to generate some waypoints
|
||||
// without fill_gaps first)
|
||||
// fill_gaps = false: continue with the last waypoint
|
||||
$opt['logic']['waypoint_pool']['fill_gaps'] = false;
|
||||
|
||||
// see config2/settings-dist.inc.php
|
||||
$opt['template']['default']['locale'] = 'DE'; // may be overwritten by $opt['domain'][...]['locale']
|
||||
|
||||
$opt['template']['locales']['DE']['show'] = true;
|
||||
|
||||
@@ -33,10 +33,6 @@
|
||||
//id of the node
|
||||
$oc_nodeid = 4;
|
||||
|
||||
// waypoint prefix of the node
|
||||
// OC = oc.de, OP = oc.pl, ... AA = local development
|
||||
$oc_waypoint_prefix = 'AA';
|
||||
|
||||
//name of the cookie
|
||||
$opt['cookie']['name'] = 'oc_devel';
|
||||
$opt['cookie']['path'] = '/';
|
||||
@@ -122,7 +118,25 @@
|
||||
|
||||
$opt['translate']['debug'] = false;
|
||||
|
||||
// see config2/settings-dist.inc.php
|
||||
// copy of config2/settings-dist.inc.php
|
||||
/* pregenerated waypoint list for new caches
|
||||
* - Waypoint prefix (OC, OP, OZ etc.)
|
||||
* - When pool contains less than min_count, generation process starts
|
||||
* and fills up the pool until max_count is reached.
|
||||
*/
|
||||
$opt['logic']['waypoint_pool']['prefix'] = 'AA';
|
||||
$opt['logic']['waypoint_pool']['min_count'] = 1000;
|
||||
$opt['logic']['waypoint_pool']['max_count'] = 2000;
|
||||
// chars used for waypoints. Remember to reinstall triggers and clear cache_waypoint_pool after changing
|
||||
$opt['logic']['waypoint_pool']['valid_chars'] = '0123456789ABCDEF';
|
||||
// fill_gaps = true: search for gaps between used waypoints and fill up these gaps
|
||||
// (fill_gaps is slow and CPU intensive on database server. For
|
||||
// productive servers you may want to generate some waypoints
|
||||
// without fill_gaps first)
|
||||
// fill_gaps = false: continue with the last waypoint
|
||||
$opt['logic']['waypoint_pool']['fill_gaps'] = false;
|
||||
|
||||
// see config2/settings-dist.inc.php
|
||||
$opt['template']['default']['locale'] = 'DE'; // may be overwritten by $opt['domain'][...]['locale']
|
||||
$opt['template']['default']['country'] = 'DE'; // may be overwritten by $opt['domain'][...]['country']
|
||||
|
||||
|
||||
160
htdocs/util2/cron/modules/cache_waypoint_pool.class.php
Normal file
160
htdocs/util2/cron/modules/cache_waypoint_pool.class.php
Normal file
@@ -0,0 +1,160 @@
|
||||
<?php
|
||||
/***************************************************************************
|
||||
* For license information see doc/license.txt
|
||||
*
|
||||
* Unicode Reminder メモ
|
||||
*
|
||||
* This cronjob fills the table cache_waypoint_pool with waypoints that
|
||||
* can be assigned to new caches. The code is cpu intensive on database
|
||||
* server.
|
||||
***************************************************************************/
|
||||
|
||||
checkJob(new cache_waypoint_pool());
|
||||
|
||||
class cache_waypoint_pool
|
||||
{
|
||||
var $name = 'cache_waypoint_pool';
|
||||
var $interval = 604800; // once a week
|
||||
|
||||
function run()
|
||||
{
|
||||
global $opt;
|
||||
$nLastInsertsCount = 1;
|
||||
|
||||
// check if the pool needs to be filled up and repeat until the
|
||||
$nPoolSize = $this->getCurrentPoolSize();
|
||||
if ($nPoolSize < $opt['logic']['waypoint_pool']['min_count'])
|
||||
{
|
||||
while (($nPoolSize < $opt['logic']['waypoint_pool']['max_count']) && ($nLastInsertsCount > 0))
|
||||
{
|
||||
$nLastInsertsCount = $this->fill($opt['logic']['waypoint_pool']['max_count'] - $nPoolSize);
|
||||
$nPoolSize = $this->getCurrentPoolSize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getCurrentPoolSize()
|
||||
{
|
||||
return sql_value("SELECT COUNT(*) FROM `cache_waypoint_pool`", 0);
|
||||
}
|
||||
|
||||
function fill($max_inserts_count)
|
||||
{
|
||||
global $opt;
|
||||
|
||||
$rowCount = 0;
|
||||
$nInsertCount = 0;
|
||||
|
||||
if ($opt['logic']['waypoint_pool']['fill_gaps'] == true)
|
||||
{
|
||||
// query the first unused waypoint (between other waypoints)
|
||||
$rsStartWp = sql("SELECT SQL_BUFFER_RESULT DECTOWP(WPTODEC(`c`.`wp_oc`, '&1')+1, '&1') AS `free_wp`
|
||||
FROM `caches` AS `c`
|
||||
LEFT JOIN `caches` as `cNext` ON DECTOWP(WPTODEC(`c`.`wp_oc`, '&1')+1, '&1')=`cNext`.`wp_oc`
|
||||
LEFT JOIN `cache_waypoint_pool` ON DECTOWP(WPTODEC(`c`.`wp_oc` ,'&1')+1, '&1')=`cache_waypoint_pool`.`wp_oc`
|
||||
WHERE `c`.`wp_oc` REGEXP '&2'
|
||||
AND ISNULL(`cNext`.`wp_oc`)
|
||||
AND ISNULL(`cache_waypoint_pool`.`wp_oc`)
|
||||
ORDER BY `free_wp` ASC
|
||||
LIMIT 250",
|
||||
$opt['logic']['waypoint_pool']['prefix'],
|
||||
'^' . $opt['logic']['waypoint_pool']['prefix'] . '[' . $opt['logic']['waypoint_pool']['valid_chars'] . ']{1,}$');
|
||||
}
|
||||
else
|
||||
{
|
||||
// query the last used waypoint
|
||||
$rsStartWp = sql("SELECT SQL_BUFFER_RESULT DECTOWP(MAX(dec_wp)+1, '&2') AS `free_wp`
|
||||
FROM (
|
||||
SELECT MAX(WPTODEC(`wp_oc`, '&2')) AS dec_wp
|
||||
FROM `caches`
|
||||
WHERE `wp_oc` REGEXP '&1'
|
||||
UNION
|
||||
SELECT MAX(WPTODEC(`wp_oc`, '&2')) AS dec_wp
|
||||
FROM `cache_waypoint_pool`
|
||||
) AS tbl",
|
||||
'^' . $opt['logic']['waypoint_pool']['prefix'] . '[' . $opt['logic']['waypoint_pool']['valid_chars'] . ']{1,}$',
|
||||
$opt['logic']['waypoint_pool']['prefix']);
|
||||
}
|
||||
|
||||
while (($rStartWp = sql_fetch_assoc($rsStartWp)) && ($nInsertCount < $max_inserts_count))
|
||||
{
|
||||
$free_wp = $rStartWp['free_wp'];
|
||||
if ($free_wp == '') $free_wp = $opt['logic']['waypoint_pool']['prefix'] . '0001';
|
||||
$nInsertCount += $this->fill_turn($free_wp, $max_inserts_count - $nInsertCount);
|
||||
$rowCount++;
|
||||
}
|
||||
sql_free_result($rsStartWp);
|
||||
|
||||
if ($rowCount == 0)
|
||||
{
|
||||
// new database ...
|
||||
$nInsertCount += $this->fill_turn($opt['logic']['waypoint_pool']['prefix'] . '0001', $max_inserts_count);
|
||||
}
|
||||
|
||||
return $nInsertCount;
|
||||
}
|
||||
|
||||
// search for the next free range and use that waypoints to fill the waypoint pool
|
||||
function fill_turn($start_wp, $max_inserts_count)
|
||||
{
|
||||
global $opt;
|
||||
|
||||
// query the end of this waypoint range
|
||||
$end_wp = sql_value("SELECT DECTOWP(MIN(dec_wp), '&3')
|
||||
FROM (
|
||||
SELECT MIN(WPTODEC(`wp_oc`, '&3')) AS dec_wp
|
||||
FROM `caches`
|
||||
WHERE WPTODEC(`wp_oc`, '&3')>WPTODEC('&1', '&3')
|
||||
AND `wp_oc` REGEXP '&2'
|
||||
UNION
|
||||
SELECT MIN(WPTODEC(`wp_oc`, '&3')) AS dec_wp
|
||||
FROM `cache_waypoint_pool`
|
||||
WHERE WPTODEC(`wp_oc`, '&3')>WPTODEC('&1', '&3')
|
||||
) AS tbl",
|
||||
$opt['logic']['waypoint_pool']['prefix'] . '100000',
|
||||
$start_wp,
|
||||
'^' . $opt['logic']['waypoint_pool']['prefix'] . '[' . $opt['logic']['waypoint_pool']['valid_chars'] . ']{1,}$',
|
||||
$opt['logic']['waypoint_pool']['prefix']);
|
||||
|
||||
// now, we have start and end waypoints ...
|
||||
$nWaypointsGenerated = 0;
|
||||
while (($nWaypointsGenerated < $max_inserts_count) && ($start_wp != $end_wp))
|
||||
{
|
||||
sql("INSERT INTO `cache_waypoint_pool` (`wp_oc`) VALUES ('&1')", $start_wp);
|
||||
$nWaypointsGenerated++;
|
||||
$start_wp = $this->increment_waypoint($start_wp, $opt['logic']['waypoint_pool']['prefix']);
|
||||
}
|
||||
|
||||
return $nWaypointsGenerated;
|
||||
}
|
||||
|
||||
// see mysql functions in doc/sql/stored-proc/maintain.php for explanation
|
||||
function increment_waypoint($wp, $prefix)
|
||||
{
|
||||
global $opt;
|
||||
|
||||
$wp_chars = $opt['logic']['waypoint_pool']['valid_chars'];
|
||||
$b36_chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||
|
||||
if (substr($wp, 0, 2) != $prefix)
|
||||
return '';
|
||||
|
||||
$wp_value = substr($wp, 2);
|
||||
$b36_value = '';
|
||||
for ($i = 0; $i < strlen($wp_value); $i++)
|
||||
$b36_value .= substr($b36_chars, strpos($wp_chars, substr($wp_value, $i, 1)), 1);
|
||||
|
||||
$dec_value = base_convert($b36_value, strlen($wp_chars), 10)+1;
|
||||
$b36_value = strtoupper(base_convert($dec_value, 10, strlen($wp_chars)));
|
||||
|
||||
$wp_value = '';
|
||||
for ($i = 0; $i < strlen($b36_value); $i++)
|
||||
$wp_value .= substr($wp_chars, strpos($b36_chars, substr($b36_value, $i, 1)), 1);
|
||||
|
||||
if (strlen($wp_value) < 4)
|
||||
return $prefix . substr('0000' . $wp_value, -4);
|
||||
else
|
||||
return $prefix . $wp_value;
|
||||
}
|
||||
}
|
||||
?>
|
||||
Reference in New Issue
Block a user