Merge pull request #52 from wrygiel/okapi

OKAPI Project update (r495).
This commit is contained in:
ocoliver 2012-11-17 11:25:03 -08:00
commit a01305e002
21 changed files with 343 additions and 109 deletions

View File

@ -759,7 +759,7 @@ class Okapi
{
public static $data_store;
public static $server;
public static $revision = 483; # This gets replaced in automatically deployed packages
public static $revision = 500; # This gets replaced in automatically deployed packages
private static $okapi_vars = null;
/** Get a variable stored in okapi_vars. If variable not found, return $default. */
@ -1449,10 +1449,6 @@ class Okapi
)
);
private static $cache_statuses = array(
'Available' => 1, 'Temporarily unavailable' => 2, 'Archived' => 3
);
/** E.g. 'Traditional' => 2. For unknown names throw an Exception. */
public static function cache_type_name2id($name)
{
@ -1479,6 +1475,10 @@ class Okapi
return "Other";
}
private static $cache_statuses = array(
'Available' => 1, 'Temporarily unavailable' => 2, 'Archived' => 3
);
/** E.g. 'Available' => 1. For unknown names throws an Exception. */
public static function cache_status_name2id($name)
{
@ -1501,6 +1501,64 @@ class Okapi
return $reversed[$id];
return 'Archived';
}
private static $cache_sizes = array(
'none' => 7,
'nano' => 8,
'micro' => 2,
'small' => 3,
'regular' => 4,
'large' => 5,
'xlarge' => 6,
'other' => 1,
);
/** E.g. 'micro' => 2. For unknown names throw an Exception. */
public static function cache_size2_to_sizeid($size2)
{
if (isset(self::$cache_sizes[$size2]))
return self::$cache_sizes[$size2];
throw new Exception("Method cache_size2_to_sizeid called with invalid size2 '$size2'.");
}
/** E.g. 2 => 'micro'. For unknown ids returns "other". */
public static function cache_sizeid_to_size2($id)
{
static $reversed = null;
if ($reversed == null)
{
$reversed = array();
foreach (self::$cache_sizes as $key => $value)
$reversed[$value] = $key;
}
if (isset($reversed[$id]))
return $reversed[$id];
return "other";
}
/** Maps OKAPI's 'size2' values to opencaching.com (OX) size codes. */
private static $cache_OX_sizes = array(
'none' => null,
'nano' => 1.3,
'micro' => 2.0,
'small' => 3.0,
'regular' => 3.8,
'large' => 4.6,
'xlarge' => 4.9,
'other' => null,
);
/**
* E.g. 'micro' => 2.0, 'other' => null. For unknown names throw an
* Exception. Note, that this is not a bijection ('none' are 'other' are
* both null).
*/
public static function cache_size2_to_oxsize($size2)
{
if (array_key_exists($size2, self::$cache_OX_sizes))
return self::$cache_OX_sizes[$size2];
throw new Exception("Method cache_size2_to_oxsize called with invalid size2 '$size2'.");
}
/**
* E.g. 'Found it' => 1. For unsupported names throws Exception.
@ -1578,9 +1636,18 @@ class Cache
* Save object $value under the key $key. Store this object for
* $timeout seconds. $key must be a string of max 64 characters in length.
* $value might be any serializable PHP object.
*
* If $timeout is null, then the object will be treated as persistent
* (the Cache will do its best to NEVER remove it).
*/
public static function set($key, $value, $timeout)
{
if ($timeout == null)
{
# The current cache implementation is ALWAYS persistent, so we will
# just replace it with a big value.
$timeout = 100*365*86400;
}
Db::execute("
replace into okapi_cache (`key`, value, expires)
values (
@ -1613,6 +1680,12 @@ class Cache
{
if (count($dict) == 0)
return;
if ($timeout == null)
{
# The current cache implementation is ALWAYS persistent, so we will
# just replace it with a big value.
$timeout = 100*365*86400;
}
$entries = array();
foreach ($dict as $key => $value)
{

View File

@ -16,6 +16,7 @@ namespace okapi\cronjobs;
use Exception;
use okapi\Okapi;
use okapi\BadRequest;
use okapi\Settings;
use okapi\OkapiLock;
use okapi\OkapiExceptionHandler;
@ -43,6 +44,7 @@ class CronJobController
new CheckCronTab2(),
new ChangeLogWriterJob(),
new ChangeLogCleanerJob(),
new ChangeLogCheckerJob(),
new AdminStatsSender(),
new LocaleChecker(),
new FulldumpGeneratorJob(),
@ -93,13 +95,27 @@ class CronJobController
$next_run = $cronjob->get_next_scheduled_run(isset($schedule[$name]) ? $schedule[$name] : time());
}
$schedule[$name] = $next_run;
Cache::set("cron_schedule", $schedule, 30*86400);
}
}
# Remove "stale" schedule keys (those which are no longer declared).
$fixed_schedule = array();
foreach (self::get_enabled_cronjobs() as $cronjob)
{
$name = $cronjob->get_name();
$fixed_schedule[$name] = $schedule[$name];
}
unset($schedule);
# Return the nearest scheduled event time.
$nearest = time() + 3600;
foreach ($schedule as $name => $time)
foreach ($fixed_schedule as $name => $time)
if ($time < $nearest)
$nearest = $time;
Cache::set("cron_schedule", $schedule, 30*86400);
Cache::set("cron_schedule", $fixed_schedule, 30*86400);
$lock->release();
return $nearest;
}
@ -446,6 +462,22 @@ class ChangeLogWriterJob extends Cron5Job
}
}
/**
* Once per day, compares alle caches to the cached versions
* kept by the 'replicate' module. If it finds any inconsistencies, it
* emails the developers (such inconsistencies shouldn't happen) and it changes
* the okapi_syncbase column accordingly. See issue 157.
*/
class ChangeLogCheckerJob extends Cron5Job
{
public function get_period() { return 86400; }
public function execute()
{
require_once($GLOBALS['rootpath']."okapi/services/replicate/replicate_common.inc.php");
ReplicateCommon::verify_clog_consistency();
}
}
/**
* Once per week, generates the fulldump archive.
*/
@ -473,17 +505,26 @@ class TileTreeUpdater extends Cron5Job
# No update necessary.
} elseif ($tiletree_revision < $current_clog_revision) {
require_once($GLOBALS['rootpath']."okapi/services/caches/map/replicate_listener.inc.php");
if ($current_clog_revision - $tiletree_revision < 100000) # In the middle of 2012, OCPL generated 30000 entries per week
if ($current_clog_revision - $tiletree_revision < 30000) # In the middle of 2012, OCPL generated 30000 entries per week
{
for ($i=0; $i<100; $i++) # This gives us no more than 20000 (?) at a time.
for ($timeout = time() + 240; time() < $timeout; ) # Try to stop after 4 minutes.
{
$response = OkapiServiceRunner::call('services/replicate/changelog', new OkapiInternalRequest(
new OkapiInternalConsumer(), null, array('since' => $tiletree_revision)));
\okapi\services\caches\map\ReplicateListener::receive($response['changelog']);
$tiletree_revision = $response['revision'];
Okapi::set_var('clog_followup_revision', $tiletree_revision);
if (!$response['more'])
break;
try {
$response = OkapiServiceRunner::call('services/replicate/changelog', new OkapiInternalRequest(
new OkapiInternalConsumer(), null, array('since' => $tiletree_revision)));
\okapi\services\caches\map\ReplicateListener::receive($response['changelog']);
$tiletree_revision = $response['revision'];
Okapi::set_var('clog_followup_revision', $tiletree_revision);
if (!$response['more'])
break;
} catch (BadRequest $e) {
# Invalid 'since' parameter? May happen whne crontab was
# not working for more than 10 days. Or, just after OKAPI
# is installed (and this is the first time this cronjob
# if being run).
\okapi\services\caches\map\ReplicateListener::reset();
Okapi::set_var('clog_followup_revision', $current_clog_revision);
}
}
} else {
# Some kind of bigger update. Resetting TileTree might be a better option.

View File

@ -27,6 +27,7 @@ class WebService
return array(
'name' => (string)$attrs['name'],
'is_required' => $arg_node->getName() == 'req',
'is_deprecated' => (isset($attrs['class']) && (strpos($attrs['class'], 'deprecated') !== false)),
'class' => 'public',
'description' =>
(isset($attrs['default']) ? ("<p>Default value: <b>".$attrs['default']."</b></p>") : "").
@ -120,16 +121,21 @@ class WebService
$result['arguments'][] = array(
'name' => 'format',
'is_required' => false,
'is_deprecated' => false,
'class' => 'common-formatting',
'description' => "<i>Standard <a href='".Settings::get('SITE_URL')."okapi/introduction.html#common-formatting'>common formatting</a> argument.</i>"
);
$result['arguments'][] = array(
'name' => 'callback',
'is_required' => false,
'is_deprecated' => false,
'class' => 'common-formatting',
'description' => "<i>Standard <a href='".Settings::get('SITE_URL')."okapi/introduction.html#common-formatting'>common formatting</a> argument.</i>"
);
}
foreach ($result['arguments'] as &$arg_ref)
if ($arg_ref['is_deprecated'])
$arg_ref['class'] .= " deprecated";
if (!$docs->returns)
throw new Exception("Missing <returns> element in the $methodname.xml file. ".
"If your method does not return anything, you should document in nonetheless.");

View File

@ -38,11 +38,12 @@
<ul>
<li><b>name</b> - name of an argument,</li>
<li><b>is_required</b> - boolean, true if the argument is required,</li>
<li><b>is_deprecated</b> - boolean, true if the argument is deprecated,</li>
<li><b>description</b> - HTML-formatted description of an argument.</li>
<li>
<p><b>class</b> - one of the following values: <i>public</i>,
<i>inherited</i> or <i>common-formatting</i> (other values might be
introduced in future).</p>
<p><b>class</b> - space separated list of the following values: <i>public</i>,
<i>inherited</i>, <i>common-formatting</i> and <i>deprecated</i>
(other values might be introduced in future).</p>
<p>Currently these values do not mean anything specific. They are
used for different coloring/styling in the documentation pages.</p>
</li>

View File

@ -36,23 +36,16 @@ class WebService
'Other' => 'Unknown Cache'
);
/** Maps OpenCaching cache sizes Geocaching.com size codes. */
/** Maps OKAPI's 'size2' values to geocaching.com size codes. */
public static $cache_GPX_sizes = array(
1 => 'Micro',
2 => 'Small',
3 => 'Regular',
4 => 'Large',
5 => 'Large',
null => 'Virtual'
);
/** Maps OpenCaching cache sizes opencaching.com (OX) size codes. */
public static $cache_OX_sizes = array(
1 => 2,
2 => 3,
3 => 4,
4 => 5,
5 => 5,
null => null
'none' => 'Virtual',
'nano' => 'Micro',
'micro' => 'Micro',
'small' => 'Small',
'regular' => 'Regular',
'large' => 'Large',
'xlarge' => 'Large',
'other' => 'Other',
);
public static function call(OkapiRequest $request)
@ -121,7 +114,7 @@ class WebService
# We can get all the data we need from the services/caches/geocaches method.
# We don't need to do any additional queries here.
$fields = 'code|name|location|date_created|url|type|status|size'.
$fields = 'code|name|location|date_created|url|type|status|size|size2|oxsize'.
'|difficulty|terrain|description|hint|rating|owner|url|internal_id';
if ($vars['images'] != 'none')
$fields .= "|images";
@ -149,7 +142,6 @@ class WebService
new OkapiInternalConsumer(), null, array()));
$vars['cache_GPX_types'] = self::$cache_GPX_types;
$vars['cache_GPX_sizes'] = self::$cache_GPX_sizes;
$vars['cache_OX_sizes'] = self::$cache_OX_sizes;
$response = new OkapiHttpResponse();
$response->content_type = "text/xml; charset=utf-8";

View File

@ -35,7 +35,7 @@ http://www.gsak.net/xmlv1/5 http://www.gsak.net/xmlv1/5/gsak.xsd
<groundspeak:placed_by><?= htmlspecialchars($c['owner']['username'], ENT_COMPAT, 'UTF-8') ?></groundspeak:placed_by>
<groundspeak:owner id="<?= $c['owner']['uuid'] ?>"><?= htmlspecialchars($c['owner']['username'], ENT_COMPAT, 'UTF-8') ?></groundspeak:owner>
<groundspeak:type><?= $vars['cache_GPX_types'][$c['type']] ?></groundspeak:type>
<groundspeak:container><?= $vars['cache_GPX_sizes'][$c['size']] ?></groundspeak:container>
<groundspeak:container><?= $vars['cache_GPX_sizes'][$c['size2']] ?></groundspeak:container>
<groundspeak:difficulty><?= $c['difficulty'] ?></groundspeak:difficulty>
<groundspeak:terrain><?= $c['terrain'] ?></groundspeak:terrain>
<groundspeak:long_description html="True">
@ -121,7 +121,7 @@ http://www.gsak.net/xmlv1/5 http://www.gsak.net/xmlv1/5/gsak.xsd
<ox:ratings>
<? if ($c['rating'] !== null) { ?><ox:awesomeness><?= $c['rating'] ?></ox:awesomeness><? } ?>
<ox:difficulty><?= $c['difficulty'] ?></ox:difficulty>
<? if ($c['size'] !== null) { ?><ox:size><?= $vars['cache_OX_sizes'][$c['size']] ?></ox:size><? } ?>
<? if ($c['oxsize'] !== null) { ?><ox:size><?= $c['oxsize'] ?></ox:size><? } ?>
<ox:terrain><?= $c['terrain'] ?></ox:terrain>
</ox:ratings>
<? if ($vars['attrs'] == 'ox:tags' && count($c['attrnames']) > 0) { /* Does user want us to include ox:tags? */ ?>

View File

@ -89,8 +89,25 @@
</li>
<li><b>founds</b> - number of times the geocache was successfully found,</li>
<li><b>notfounds</b> - number of times the geocache was not found,</li>
<li><b>size</b> - float (between 1 and 5), size rating of the container, or
<b>null</b> if geocache does not have a container,</li>
<li class='deprecated'>
<b>size</b> - deprecated
(<a href='http://code.google.com/p/opencaching-api/issues/detail?id=155'>why?</a>),
use <b>size2</b> instead. Float (between 1 and 5), size rating of the container, or
<b>null</b> if geocache does not have a container,
</li>
<li>
<p><b>size2</b> - string indicating the size od the container, so called
"size2 code". One of the following values:
'none', 'nano', 'micro', 'small', 'regular', 'large', 'xlarge', 'other'.</p>
</li>
<li>
<p><b>oxsize</b> - float (between 1 and 5) or null, this is a size rating
variant, compatible with the one used by opencaching.com (and lately,
Garmin GPS devices).</p>
<p><b>Note:</b> The mapping is undocumented and may change without notice.</p>
<p><b>Note:</b> Some of OC's size values cannot be properly mapped to <b>oxcode</b>,
i.e. the 'other' size.</p>
</li>
<li><b>difficulty</b> - float (between 1 and 5), difficulty rating of the cache,</li>
<li><b>terrain</b> - float (between 1 and 5), terrain rating of the cache,</li>
<li>

View File

@ -26,7 +26,7 @@ class WebService
private static $valid_field_names = array('code', 'name', 'names', 'location', 'type',
'status', 'url', 'owner', 'distance', 'bearing', 'bearing2', 'bearing3', 'is_found',
'is_not_found', 'founds', 'notfounds', 'size', 'difficulty', 'terrain',
'is_not_found', 'founds', 'notfounds', 'size', 'size2', 'oxsize', 'difficulty', 'terrain',
'rating', 'rating_votes', 'recommendations', 'req_passwd', 'description',
'descriptions', 'hint', 'hints', 'images', 'attrnames', 'latest_logs',
'my_notes', 'trackables_count', 'trackables', 'alt_wpts', 'last_found',
@ -204,7 +204,23 @@ class WebService
case 'is_not_found': /* handled separately */ break;
case 'founds': $entry['founds'] = $row['founds'] + 0; break;
case 'notfounds': $entry['notfounds'] = $row['notfounds'] + 0; break;
case 'size': $entry['size'] = ($row['size'] < 7) ? (float)($row['size'] - 1) : null; break;
case 'size':
# Deprecated. Leave it for backward-compatibility. See issue 155.
switch (Okapi::cache_sizeid_to_size2($row['size']))
{
case 'none': $entry['size'] = null; break;
case 'nano': $entry['size'] = 1.0; break; # same as micro
case 'micro': $entry['size'] = 1.0; break;
case 'small': $entry['size'] = 2.0; break;
case 'regular': $entry['size'] = 3.0; break;
case 'large': $entry['size'] = 4.0; break;
case 'xlarge': $entry['size'] = 5.0; break;
case 'other': $entry['size'] = null; break; # same as none
default: throw new Exception();
}
break;
case 'size2': $entry['size2'] = Okapi::cache_sizeid_to_size2($row['size']); break;
case 'oxsize': $entry['oxsize'] = Okapi::cache_size2_to_oxsize(Okapi::cache_sizeid_to_size2($row['size'])); break;
case 'difficulty': $entry['difficulty'] = round($row['difficulty'] / 2.0, 1); break;
case 'terrain': $entry['terrain'] = round($row['terrain'] / 2.0, 1); break;
case 'rating':

View File

@ -57,7 +57,10 @@
<p>A string "X-Y", where X and Y are integers between 1 and 5, and X &lt;= Y.
Only caches with difficulty rating between these numbers (inclusive) will be returned.</p>
</opt>
<opt name='size'>
<opt name='size' class='deprecated'>
<p>Deprecated. Please use <b>size2</b> instead - this will allow you to
differentiate "nano" vs. "micro" and "none" vs. "other" sizes
(<a href='http://code.google.com/p/opencaching-api/issues/detail?id=155'>details</a>).</p>
<p>A string "X-Y", where X and Y are integers between 1 and 5, and X &lt;= Y.
Only caches with size attribute between these numbers (inclusive) will be returned
(1 - micro, 5 - very big).</p>
@ -66,6 +69,13 @@
with no container included, append "|X" suffix to the value of this parameter
(e.g. "3-5|X").</p>
</opt>
<opt name='size2'>
<p>Pipe-separated list of "size2 codes". Only matching caches will be
included. The codes are: 'none', 'nano', 'micro', 'small', 'regular',
'large', 'xlarge', 'other'.</p>
<p><b>Note:</b> Not all OC servers use all of these. I.e. OCPL does not
have 'nano' nor 'other' caches (but it might have them in the future).</p>
</opt>
<opt name='rating'>
<p>A string "X-Y", where X and Y are integers between 1 and 5, and X &lt;= Y.
Only caches with an overall rating between these numbers (inclusive) will be returned

View File

@ -97,6 +97,34 @@ class SearchAssistant
$where_conds[] = "caches.type $operator ('".implode("','", array_map('mysql_real_escape_string', $types))."')";
}
#
# size2
#
if ($tmp = $request->get_parameter('size2'))
{
$operator = "in";
if ($tmp[0] == '-')
{
$tmp = substr($tmp, 1);
$operator = "not in";
}
$types = array();
foreach (explode("|", $tmp) as $name)
{
try
{
$id = Okapi::cache_size2_to_sizeid($name);
$types[] = $id;
}
catch (Exception $e)
{
throw new InvalidParam('size2', "'$name' is not a valid cache size.");
}
}
$where_conds[] = "caches.size $operator ('".implode("','", array_map('mysql_real_escape_string', $types))."')";
}
#
# status - filter by status codes
#
@ -185,11 +213,17 @@ class SearchAssistant
}
break;
case 'size':
# Deprecated. Leave it for backward-compatibility. See issue 155.
if (($min == 1) && ($max == 5) && $allow_null) {
/* no extra condition necessary */
# No extra condition necessary ('other' caches will be
# included).
} else {
# 'other' size caches will NOT be included (user must use the
# 'size2' parameter to search these). 'nano' caches will be
# included whenever 'micro' caches are included ($min=1).
$where_conds[] = "(caches.size between $min+1 and $max+1)".
($allow_null ? " or caches.size=7" : "");
($allow_null ? " or caches.size=7" : "").
(($min == 1) ? " or caches.size=8" : "");
}
break;
case 'rating':

View File

@ -65,7 +65,6 @@
set on him by the OC site. If criteria are not met, the request will
end with user error (HTTP 200, success=false).</p>
</opt>
<!--
<opt name='needs_maintenance' default='false'>
<p>Set to <b>true</b> if the user thinks that the cache needs some special attension
of its owner. Users should describe the reason for maintenance in their comments.</p>
@ -75,7 +74,6 @@
only one of those entries). Moreover, on some OC servers this flag might be
<b>completely ignored</b> (not all OC servers support this feature).</p>
</opt>
-->
<common-format-params/>
<returns>
<p>A dictionary of the following structure:</p>

View File

@ -19,7 +19,7 @@ use okapi\Settings;
class ReplicateCommon
{
private static $chunk_size = 200;
private static $logged_cache_fields = 'code|names|location|type|status|url|owner|founds|notfounds|size|difficulty|terrain|rating|rating_votes|recommendations|req_passwd|descriptions|hints|images|trackables_count|trackables|alt_wpts|last_found|last_modified|date_created|date_hidden';
private static $logged_cache_fields = 'code|names|location|type|status|url|owner|founds|notfounds|size|size2|oxsize|difficulty|terrain|rating|rating_votes|recommendations|req_passwd|descriptions|hints|images|trackables_count|trackables|alt_wpts|last_found|last_modified|date_created|date_hidden';
private static $logged_log_entry_fields = 'uuid|cache_code|date|user|type|comment';
@ -69,7 +69,7 @@ class ReplicateCommon
/** Check for modifications in the database and update the changelog table accordingly. */
public static function update_clog_table()
{
$now = Db::select_value("select now()");
$now = Db::select_value("select date_add(now(), interval -1 minute)"); # See issue 157.
$last_update = Okapi::get_var('last_clog_update');
if ($last_update === null)
$last_update = Db::select_value("select date_add(now(), interval -1 day)");
@ -99,7 +99,7 @@ class ReplicateCommon
foreach ($cache_code_groups as $cache_codes)
{
self::generate_changelog_entries('services/caches/geocaches', 'geocache', 'cache_codes',
'code', $cache_codes, self::$logged_cache_fields, false, true, 30*86400);
'code', $cache_codes, self::$logged_cache_fields, false, true, null);
}
# Same as above, for log entries.
@ -147,13 +147,78 @@ class ReplicateCommon
Okapi::set_var("clog_revision", $revision);
}
/**
* Scan the database and compare the current values of old entries to
* the cached values of the same entries. If differences found, update
* okapi_syncbase accordingly, and email the admins.
*
* Currently, only caches are checked (log entries are not).
*/
public static function verify_clog_consistency()
{
set_time_limit(0);
ignore_user_abort(true);
# We will SKIP the entries which have been modified SINCE one day ago.
# Such entries might have not been seen by the update_clog_table() yet
# (e.g. other long-running cronjob is preventing update_clog_table from
# running).
$cache_codes = Db::select_column("
select wp_oc
from caches
where okapi_syncbase < date_add(now(), interval -1 day);
");
$cache_code_groups = Okapi::make_groups($cache_codes, 50);
unset($cache_codes);
# For each group, get the changelog entries, but don't store them
# (the "fulldump" mode). Instead, just update the okapi_syncbase column.
$sum = 0;
foreach ($cache_code_groups as $cache_codes)
{
$entries = self::generate_changelog_entries(
'services/caches/geocaches', 'geocache', 'cache_codes',
'code', $cache_codes, self::$logged_cache_fields, true, true, null
);
foreach ($entries as $entry)
{
if ($entry['object_type'] != 'geocache')
continue;
$cache_code = $entry['object_key']['code'];
Db::execute("
update caches
set okapi_syncbase = now()
where wp_oc = '".mysql_real_escape_string($cache_code)."'
");
$sum += 1;
}
}
if ($sum > 0)
{
Okapi::mail_from_okapi(
"rygielski@mimuw.edu.pl",
"verify_clog_consistency",
"Number of invalid entries fixed: $sum\n\n".
print_r(Db::select_all("select * from okapi_vars"), true)
);
}
}
/**
* Generate OKAPI changelog entries. This method will call $feeder_method OKAPI
* service with the following parameters: array($feeder_keys_param => implode('|', $key_values),
* 'fields' => $fields). Then it will generate the changelog, based on the result.
* This looks pretty much the same for various object types, that's why it's here.
*
* If $use_cache is true, then all the dictionaries from $feeder_method will be also
* kept in OKAPI cache, for future comparison.
* kept in OKAPI cache, for future comparison.
*
* In normal mode, update the changelog and don't return anything.
* In fulldump mode, return the generated changelog entries *instead* of
* updating it.
*/
private static function generate_changelog_entries($feeder_method, $object_type, $feeder_keys_param,
$key_name, $key_values, $fields, $fulldump_mode, $use_cache, $cache_timeout = 86400)
@ -162,12 +227,21 @@ class ReplicateCommon
if ($use_cache)
{
$cache_keys = array();
$cache_keys1 = array();
$cache_keys2 = array();
foreach ($key_values as $key)
$cache_keys[] = 'clog#'.$object_type.'#'.$key;
$cached_values = Cache::get_many($cache_keys);
Cache::delete_many($cache_keys);
unset($cache_keys);
$cache_keys1[] = 'clog#'.$object_type.'#'.$key;
foreach ($key_values as $key)
$cache_keys2[] = 'clogmd5#'.$object_type.'#'.$key;
$cached_values1 = Cache::get_many($cache_keys1);
$cached_values2 = Cache::get_many($cache_keys2);
if (!$fulldump_mode)
{
Cache::delete_many($cache_keys1);
Cache::delete_many($cache_keys2);
}
unset($cache_keys1);
unset($cache_keys2);
}
# Get the current values for objects. Compare them with their previous versions
@ -185,10 +259,21 @@ class ReplicateCommon
# Currently, the object exists.
if ($use_cache)
{
$diff = self::get_diff($cached_values['clog#'.$object_type.'#'.$key], $object);
# First, compare the cached hash. The hash has much longer lifetime
# than the actual cached object.
$cached_md5 = $cached_values2['clogmd5#'.$object_type.'#'.$key];
$current_md5 = md5(serialize($object));
if ($cached_md5 == $current_md5)
{
# The object was not changed since it was last replaced.
continue;
}
$diff = self::get_diff($cached_values1['clog#'.$object_type.'#'.$key], $object);
if (count($diff) == 0)
{
# No field has changed since the object was last replaced.
# Md5 differs, but diff does not. Weird, but it can happen
# (e.g. just after the md5 extension was introduced, or if
# md5 somehow expired before the actual object did).
continue;
}
}
@ -201,13 +286,14 @@ class ReplicateCommon
if ($use_cache)
{
# Save the last-published state of the object, for future comparison.
$cached_values['clog#'.$object_type.'#'.$key] = $object;
$cached_values2['clogmd5#'.$object_type.'#'.$key] = $current_md5;
$cached_values1['clog#'.$object_type.'#'.$key] = $object;
}
}
else
{
# Currently, the object does not exist.
if ($use_cache && ($cached_values['clog#'.$object_type.'#'.$key] === false))
if ($use_cache && ($cached_values1['clog#'.$object_type.'#'.$key] === false))
{
# No need to delete, we have already published its deletion.
continue;
@ -220,7 +306,8 @@ class ReplicateCommon
if ($use_cache)
{
# Cache the fact, that the object was deleted.
$cached_values['clog#'.$object_type.'#'.$key] = false;
$cached_values2['clogmd5#'.$object_type.'#'.$key] = false;
$cached_values1['clog#'.$object_type.'#'.$key] = false;
}
}
}
@ -247,7 +334,10 @@ class ReplicateCommon
# Update the values kept in OKAPI cache.
if ($use_cache)
Cache::set_many($cached_values, $cache_timeout);
{
Cache::set_many($cached_values1, $cache_timeout);
Cache::set_many($cached_values2, null); # make it persistent
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -1,45 +0,0 @@
<?php
namespace okapi\views\attrlist;
use Exception;
use okapi\Okapi;
use okapi\Cache;
use okapi\Db;
use okapi\OkapiRequest;
use okapi\OkapiRedirectResponse;
use okapi\OkapiHttpResponse;
use okapi\ParamMissing;
use okapi\InvalidParam;
use okapi\OkapiServiceRunner;
use okapi\OkapiInternalRequest;
class View
{
public static function call()
{
# This is a hidden page for OKAPI developers. It will list all
# attributes defined in this OC installation.
$rs = Db::query("select id, language, text_long from cache_attrib order by id");
$dict = array();
while ($row = mysql_fetch_assoc($rs))
$dict[$row['id']][strtolower($row['language'])] = $row['text_long'];
$chunks = array();
foreach ($dict as $internal_id => $langs)
{
$chunks[] = "<attr code='...' internal_id='$internal_id'";
$langkeys = array_keys($langs);
sort($langkeys);
foreach ($langkeys as $langkey)
$chunks[] = " $langkey='".$langs[$langkey]."'";
$chunks[] = " />\n";
}
$response = new OkapiHttpResponse();
$response->content_type = "text/plain; charset=utf-8";
$response->body = implode("", $chunks);
return $response;
}
}

View File

@ -35,7 +35,7 @@ $m = $vars['method'];
<td class='precaption' colspan='3'>
<table><tr>
<td>Minimum Authentication: <span class='level level<?= $m['auth_options']['min_auth_level'] ?>'>Level <?= $m['auth_options']['min_auth_level'] ?></span></td>
<td>(see <a href='<?= $vars['okapi_base_url'] ?>introduction#auth_level'>Authentication Levels</a>)</td>
<td>(see <a href='<?= $vars['okapi_base_url'] ?>introduction.html#auth_levels'>Authentication Levels</a>)</td>
</tr></table>
</td>
</tr>

View File

@ -621,4 +621,5 @@ class View
private static function ver73() { Db::execute("update okapi_cache set score=1, expires=date_add(now(), interval 360 day) where `key` like 'tile/%'"); }
private static function ver74() { Db::execute("update okapi_cache set score=1, expires=date_add(now(), interval 360 day) where `key` like 'tilecaption/%'"); }
private static function ver75() { Db::execute("alter table okapi_cache modify column score float default null"); }
private static function ver76() { Db::execute("update okapi_cache set expires=date_add(now(), interval 100 year) where `key` like 'clog#geocache#%'"); }
}