晋太元中,武陵人捕鱼为业。缘溪行,忘路之远近。忽逢桃花林,夹岸数百步,中无杂树,芳草鲜美,落英缤纷。渔人甚异之,复前行,欲穷其林。 林尽水源,便得一山,山有小口,仿佛若有光。便舍船,从口入。初极狭,才通人。复行数十步,豁然开朗。土地平旷,屋舍俨然,有良田、美池、桑竹之属。阡陌交通,鸡犬相闻。其中往来种作,男女衣着,悉如外人。黄发垂髫,并怡然自乐。 见渔人,乃大惊,问所从来。具答之。便要还家,设酒杀鸡作食。村中闻有此人,咸来问讯。自云先世避秦时乱,率妻子邑人来此绝境,不复出焉,遂与外人间隔。问今是何世,乃不知有汉,无论魏晋。此人一一为具言所闻,皆叹惋。余人各复延至其家,皆出酒食。停数日,辞去。此中人语云:“不足为外人道也。”(间隔 一作:隔绝) 既出,得其船,便扶向路,处处志之。及郡下,诣太守,说如此。太守即遣人随其往,寻向所志,遂迷,不复得路。 南阳刘子骥,高尚士也,闻之,欣然规往。未果,寻病终。后遂无问津者。
|
Server : Apache System : Linux srv.rainic.com 4.18.0-553.47.1.el8_10.x86_64 #1 SMP Wed Apr 2 05:45:37 EDT 2025 x86_64 User : rainic ( 1014) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /home/stando/www/wp-content/plugins/w3-total-cache/ |
Upload File : |
<?php
namespace W3TC;
/**
* Manages data statistics.
* Metrics:
*
*/
class UsageStatistics_StorageWriter {
private $slot_interval_seconds;
private $slots_count;
private $keep_history_interval_seconds;
private $cache_storage;
/**
* Cached values, just keep state between calls
*/
private $hotspot_endtime;
private $new_hotspot_endtime = 0;
private $now;
/**
* begin_ sets the state what should it perform later
* finish reacts to that state and finishes flushing
* values:
* not_needed - no flushinig required now
* require_db - database access has to be available to decide
* flushing_began_by_cache - that process has been selected to
* flush hotspot data based on cache data state, still that has to be
* verified in database
*/
private $flush_state;
public function __construct() {
$this->cache_storage = Dispatcher::get_usage_statistics_cache();
$c = Dispatcher::config();
$this->slot_interval_seconds = $c->get_integer( 'stats.slot_seconds' );
$this->keep_history_interval_seconds =
$c->get_integer( 'stats.slots_count' ) *
$this->slot_interval_seconds;
$this->slots_count = $c->get_integer( 'stats.slots_count' );
}
public function reset() {
if ( !is_null( $this->cache_storage ) ) {
$this->cache_storage->set( 'hotspot_endtime', 0 );
}
update_site_option( 'w3tc_stats_hotspot_start', time() );
update_site_option( 'w3tc_stats_history', '' );
}
public function counter_add( $metric, $value ) {
if ( !is_null( $this->cache_storage ) ) {
$this->cache_storage->counter_add( $metric, $value );
}
}
public function get_hotspot_end() {
if ( is_null( $this->hotspot_endtime ) ) {
$v = $this->cache_storage->get( 'hotspot_endtime' );
$this->hotspot_endtime = ( isset( $v['content'] ) ? $v['content'] : 0 );
}
return $this->hotspot_endtime;
}
private function get_option_storage() {
if ( is_multisite() )
return new _OptionStorageWpmu();
else
return new _OptionStorageSingleSite();
}
public function maybe_flush_hotspot_data() {
$result = $this->begin_flush_hotspot_data();
if ( $result == 'not_needed' )
return;
$this->finish_flush_hotspot_data();
}
/**
* Returns if finish_* should be called.
* It tries to pass as litte processes as possible to
* flushing_begain if multiple processes come here
* at the same time when hotspot time ended.
*/
public function begin_flush_hotspot_data() {
$hotspot_endtime = $this->get_hotspot_end();
if ( is_null( $hotspot_endtime ) ) {
// if cache not recognized - means nothing is cached at all
// so stats not collected
return 'not_needed';
}
$hotspot_endtime_int = (int)$hotspot_endtime;
$this->now = time();
if ( $hotspot_endtime_int <= 0 ) {
$this->flush_state = 'require_db';
} elseif ( $this->now < $hotspot_endtime_int ) {
$this->flush_state = 'not_needed';
} else {
// rand value makes value unique for each process,
// so as a result next replace works as a lock
// passing only single process further
$this->new_hotspot_endtime = $this->now + $this->slot_interval_seconds +
( rand( 1, 9999 ) / 10000.0 );
$succeeded = $this->cache_storage->set_if_maybe_equals( 'hotspot_endtime',
array( 'content' => $hotspot_endtime ),
array( 'content' => $this->new_hotspot_endtime ) );
$this->flush_state =
( $succeeded ? 'flushing_began_by_cache' : 'not_needed' );
}
return $this->flush_state;
}
public function finish_flush_hotspot_data() {
$option_storage = $this->get_option_storage();
if ( $this->flush_state == 'not_needed' )
return;
if ( $this->flush_state != 'require_db' &&
$this->flush_state != 'flushing_began_by_cache' )
throw new Exception( 'unknown usage stats state ' . $this->flush_state );
// check whats there in db
$this->hotspot_endtime = $option_storage->get_hotspot_end();
$hotspot_endtime_int = (int)$this->hotspot_endtime;
if ( $this->now < $hotspot_endtime_int ) {
// update cache, since there is something old/missing in cache
$this->cache_storage->set( 'hotspot_endtime',
array( 'content' => $this->hotspot_endtime ) );
return; // not neeeded really, db state after
}
if ( $this->new_hotspot_endtime <= 0 )
$this->new_hotspot_endtime = $this->now +
$this->slot_interval_seconds +
( rand( 1, 9999 ) / 10000.0 );
if ( $hotspot_endtime_int <= 0 ) {
// no data in options, initialization
$this->cache_storage->set( 'hotspot_endtime',
array( 'content' => $this->new_hotspot_endtime ) );
update_site_option( 'w3tc_stats_hotspot_start', time() );
$option_storage->set_hotspot_end( $this->new_hotspot_endtime );
return;
}
// try to become the process who makes flushing by
// performing atomic database update
// rand value makes value unique for each process,
// so as a result next replace works as a lock
// passing only single process further
$succeeded = $option_storage->prolong_hotspot_end(
$this->hotspot_endtime, $this->new_hotspot_endtime );
if ( !$succeeded )
return;
$this->cache_storage->set( 'hotspot_endtime',
array( 'content' => $this->new_hotspot_endtime ) );
// flush data
$metrics = array();
$metrics = apply_filters( 'w3tc_usage_statistics_metrics', $metrics );
$metric_values = array();
$metric_values['timestamp_start'] = get_site_option( 'w3tc_stats_hotspot_start' );
$metric_values['timestamp_end'] = $hotspot_endtime_int;
// try to limit time between get and reset of counter value
// to loose as small as posssible
foreach ( $metrics as $metric ) {
$metric_values[$metric] = $this->cache_storage->counter_get( $metric );
$this->cache_storage->counter_set( $metric, 0 );
}
$metric_values = apply_filters( 'w3tc_usage_statistics_metric_values',
$metric_values );
$history_encoded = get_site_option( 'w3tc_stats_history' );
$history = null;
if ( !empty( $history_encoded ) )
$history = json_decode( $history_encoded, true );
if ( !is_array( $history ) )
$history = array();
$time_keep_border = time() - $this->keep_history_interval_seconds;
if ( $hotspot_endtime_int < $time_keep_border )
$history = array(
array(
'timestamp_start' => $time_keep_border,
'timestamp_end' => (int)$this->new_hotspot_endtime -
$this->slot_interval_seconds - 1
)
); // this was started too much time from now
else {
// add collected
$history[] = $metric_values;
// if we empty place later - fill it
for ( ;; ) {
$metric_values = array(
'timestamp_start' => $metric_values['timestamp_end']
);
$metric_values['timestamp_end'] =
$metric_values['timestamp_start'] + $this->slot_interval_seconds;
if ( $metric_values['timestamp_end'] < $this->now )
$history[] = $metric_values;
else
break;
}
// make sure we have at least one value in history
for ( ;count( $history ) > $this->slots_count; ) {
if ( !isset( $history[0]['timestamp_end'] ) ||
$history[0]['timestamp_end'] < $time_keep_border )
array_shift( $history );
else
break;
}
}
$history = apply_filters(
'w3tc_usage_statistics_history_set', $history );
update_site_option( 'w3tc_stats_hotspot_start', $this->now );
update_site_option( 'w3tc_stats_history', json_encode( $history ) );
}
}
/**
* Can update option by directly incrementing current value,
* not via get+set operation
*/
class _OptionStorageSingleSite {
private $option_hotspot_end = 'w3tc_stats_hotspot_end';
public function get_hotspot_end() {
global $wpdb;
$row = $wpdb->get_row( $wpdb->prepare(
'SELECT option_value ' .
'FROM ' . $wpdb->options . ' ' .
'WHERE option_name = %s LIMIT 1',
$this->option_hotspot_end ) );
if ( !is_object( $row ) )
return false;
$v = $row->option_value;
return $v;
}
public function set_hotspot_end( $new_value ) {
update_site_option( $this->option_hotspot_end, $new_value );
}
/**
* Performs atomic update of option value
* from old to new value. Makes sure that only single process updates it.
* Only single process gets true return value when multiple tries to do that.
*/
public function prolong_hotspot_end( $old_value, $new_value ) {
global $wpdb;
$q = $wpdb->prepare(
'UPDATE ' . $wpdb->options . ' ' .
'SET option_value = %s ' .
'WHERE option_name = %s AND option_value = %s', $new_value,
$this->option_hotspot_end, $old_value );
$result = $wpdb->query( $q );
$succeeded = ( $result > 0 );
return $succeeded;
}
}
/**
* Can update option by directly incrementing current value,
* not via get+set operation
*/
class _OptionStorageWpmu {
private $option_hotspot_end = 'w3tc_stats_hotspot_end';
public function get_hotspot_end() {
global $wpdb;
$row = $wpdb->get_row( $wpdb->prepare(
'SELECT meta_value ' .
'FROM ' . $wpdb->sitemeta . ' ' .
'WHERE site_id = %d AND meta_key = %s',
$wpdb->siteid, $this->option_hotspot_end ) );
if ( !is_object( $row ) )
return false;
$v = $row->meta_value;
return $v;
}
/**
* Performs atomic update of option value
* from old to new value. Makes sure that only single process updates it.
* Only single process gets true return value when multiple tries to do that.
*/
public function set_hotspot_end( $new_value ) {
update_site_option( $this->option_hotspot_end, $new_value );
}
/**
* Performs atomic update of option value
* from old to new value. Makes sure that only single process updates it.
* Only single process gets true return value when multiple tries to do that.
*/
public function prolong_hotspot_end( $old_value, $new_value ) {
global $wpdb;
$result = $wpdb->query( $wpdb->prepare(
'UPDATE ' . $wpdb->sitemeta . ' ' .
'SET meta_value = %s ' .
'WHERE site_id = %d AND meta_key = %s AND meta_value = %s',
$new_value, $wpdb->siteid, $this->option_hotspot_end, $old_value ) );
$succeeded = ( $result > 0 );
return $succeeded;
}
}