Skip to content

Instantly share code, notes, and snippets.

@atsu666
Created October 30, 2015 03:11
Show Gist options
  • Save atsu666/bdcf6197fa21ac534e8c to your computer and use it in GitHub Desktop.
Save atsu666/bdcf6197fa21ac534e8c to your computer and use it in GitHub Desktop.
a-blog cmsのキャッシュ処理周り
//-------
// cache
define('ZIP_USE', !DEBUG_MODE and !!ZIP_ENABLE and ('on' == config('zip_http')));
if ( 1
and !DEBUG_MODE
and ('on' == config('cache'))
and (!SID or (config('subscriber_cache') === 'on' and ACMS_RAM::userAuth(SUID) === 'subscriber' and !$Q->get('admin')))
and !(is_ajax() and config('ajax_nocache') === 'on' and $GetQuery->get('nocache') === 'yes')
and !HTTPS
and !ACMS_POST
) {
//------
// CHID
define('CHID', md5(REQUEST_URL.RID));
//-----------
// publishes
$SQL = SQL::newSelect('cache');
$SQL->addWhereIn('cache_status', array('generating', 'regenerating'));
$SQL->addWhereOpr('cache_expire', date('Y-m-d H:i:s', REQUEST_TIME), '>');
$SQL->addWhereOpr('cache_blog_id', BID);
$SQL->setLimit(MAX_PUBLISHES);
$publishes = count($DB->query($SQL->get(dsn()), 'all'));
// 作ろうとしているCHIDを探索する
$SQL = SQL::newSelect('cache');
$SQL->addWhereOpr('cache_id', CHID);
// キャッシュ制御
// 他の子プロセス(prefork時のこと、worker時であればスレッドと言うべき?)を考慮していて少々分岐が多い
do {
//-------------------
// not generated yet
if ( !($row = $DB->query($SQL->get(dsn()), 'row')) ) {
// 同時publishの制限数を超えたらここで中断(503 Service Unavailable)する
if ( MAX_PUBLISHES <= $publishes ) {
define('PUBLISHING', 'fail');
userErrorLog('ACMS Warning: Cache Max Publishes Publish.');
die503('Max Publishes Publish');
}
// キャッシュ生成中であることを予約
$SQL = SQL::newInsert('cache');
$SQL->addInsert('cache_id', CHID);
$SQL->addInsert('cache_data', '');
$SQL->addInsert('cache_expire', date('Y-m-d H:i:s', REQUEST_TIME + MAX_EXECUTION_TIME));
$SQL->addInsert('cache_status', 'generating');
$SQL->addInsert('cache_blog_id', BID);
$DB->query($SQL->get(dsn()), 'exec');
// タッチの差で、ほかの子プロセスが予約していたら、インサートに失敗しているはずなので中断する
// 成功していればブロックを抜ける
if ( !!$DB->affected_rows() ) {
break;
} else {
define('PUBLISHING', 'fail');
userErrorLog('ACMS Warning: Cahce Generating Double Insert.');
die503('Generating Double Insert');
}
}
$expire = $row['cache_expire'];
$status = $row['cache_status'];
$now = date('Y-m-d H:i:s');
$execution = date('Y-m-d H:i:s', REQUEST_TIME + MAX_EXECUTION_TIME);
// 予約済み・または生成済み
switch ( $status ) {
case 'generated':
if ( MAX_PUBLISHES <= $publishes ) {
// 同時publishの制限をこえてたら、あきらめて古いキャッシュを利用する
httpStatusCode('200 OK Old Generated');
break;
} else if ( $expire <= $now ) {
// 賞味期限切れだったら作り直しの予約
$SQL = SQL::newUpdate('cache');
$SQL->addUpdate('cache_expire', $execution);
$SQL->addUpdate('cache_status', 'regenerating');
$SQL->addWhereOpr('cache_id', CHID);
$SQL->addWhereOpr('cache_status', 'generated');
$SQL->addWhereOpr('cache_blog_id', BID);
$DB->query($SQL->get(dsn()), 'exec');
if ( !!$DB->affected_rows() ) {
// 賞味期限切れから再生成が成立したとき
break 2;
} else {
// 作り直しの予約が他でされてたら、それは他に任せて古いキャッシュを利用する
httpStatusCode('200 OK Double Generated Exception');
break;
}
} else {
httpStatusCode($row['cache_http_status_code']);
break;
}
case 'generating':
// regeneratingでないので、利用できるキャッシュがない
if ( MAX_PUBLISHES <= $publishes ) {
define('PUBLISHING', 'fail');
userErrorLog('ACMS Warning: Cache Max Publishes Generating.');
die503('Max Publishes Generating');
} else if ( $expire <= $now ) {
// 先行するgeneratingの失敗を救済してる部分
$SQL = SQL::newUpdate('cache');
$SQL->addUpdate('cache_expire', $execution);
$SQL->addWhereOpr('cache_id', CHID);
$SQL->addWhereOpr('cache_status', 'generating');
$SQL->addWhereOpr('cache_expire', $now, '<=');
$SQL->addWhereOpr('cache_blog_id', BID);
$DB->query($SQL->get(dsn()), 'exec');
if ( !!$DB->affected_rows() || config('cache_publish_fail_continue') === 'on' ) {
// 有効な制限時間(timeout)を超えてgeneratingしてるのがいたら、自分が試行
break 2;
} else {
// だれかが試行中なら、あきらめて中断
define('PUBLISHING', 'fail');
userErrorLog('ACMS Warning: Cache Double Generating Exception.');
die503('Double Generating Exception');
}
} else if ( config('cache_publish_fail_continue') === 'on' ) {
break 2;
} else {
// 他に試行中のがいそうなので、あきらめて中断
define('PUBLISHING', 'fail');
userErrorLog('ACMS Warning: Cache Double Generating Expire.');
die503('Double Generating Expire');
}
case 'regenerating':
// generatingとの違いは、使えるキャッシュがあるので古いキャッシュを利用する
if ( MAX_PUBLISHES <= $publishes ) {
httpStatusCode('200 OK Old Regenerating');
break;
} else if ( $expire <= $now ) {
$SQL = SQL::newUpdate('cache');
$SQL->addUpdate('cache_expire', $execution);
$SQL->addWhereOpr('cache_id', CHID);
$SQL->addWhereOpr('cache_status', 'regenerating');
$SQL->addWhereOpr('cache_expire', $now, '<=');
$SQL->addWhereOpr('cache_blog_id', BID);
$DB->query($SQL->get(dsn()), 'exec');
if ( !!$DB->affected_rows() ) {
break 2;
} else {
httpStatusCode('200 OK Double Regenerating Exception');
break;
}
} else {
httpStatusCode('200 OK Double Regenerating Expire');
break;
}
}
//-----------
// generated
define('PUBLISHING', 'static');
if ( '200 OK' === httpStatusCode() ) {
//-------------
//client cache
$pTime = strtotime($expire) - config('cache_expire');
header('Last-Modified: '.date('r', $pTime));
header('Expires: '.date('r', REQUEST_TIME + config('cache_expire_client')));
if ( IF_MODIFIED_SINCE and strtotime(IF_MODIFIED_SINCE) >= $pTime ) {
httpStatusCode('304 Not Modified');
die(header(PROTOCOL.' 304 Not Modified'));
}
}
header(PROTOCOL.' '.httpStatusCode());
header('Content-type: '.$row['cache_mime'].'; charset='.$row['cache_charset']);
$contents = $row['cache_data'];
if ( ZIP_USE ) {
header('Content-Encoding: gzip');
header('Vary: Accept-Encoding');
} else {
$contents = gzdecode($contents);
}
die($contents);
} while ( false );
}
if ( !defined('CHID') ) define('CHID', null);
if ( !defined('PUBLISHING') ) define('PUBLISHING', 'dynamic');
// cmsの処理...
//------------
// save cache
if ( !!CHID ) {
$SQL = SQL::newUpdate('cache');
$SQL->addUpdate('cache_mime', MIME_TYPE);
$SQL->addUpdate('cache_charset', config('charset'));
$SQL->addUpdate('cache_http_status_code', httpStatusCode());
$SQL->addUpdate('cache_data', $contents);
$SQL->addUpdate('cache_status', 'generated');
$SQL->addUpdate('cache_expire', date('Y-m-d H:i:s', REQUEST_TIME + intval(config('cache_expire'))));
$SQL->addWhereOpr('cache_id', CHID);
$DB->query($SQL->get(dsn()), 'exec');
// キャッシュ生成をキックとして、メール添付用アーカイブフォルダをクリアする
new ACMS_POST_Form_Cleartemp();
}
//-------------------------
// シャットダウン時に実行
function shutdown()
{
if ( defined('SESSION_NEXT_ID') and SESSION_NEXT_ID ) {
$SQL = SQL::newUpdate('session');
$SQL->addUpdate('session_data', acmsSerialize(Field::singleton('session')));
$SQL->addUpdate('session_expire', SESSION_EXPIRE);
if ( defined('SESSION_UPDATE') and SESSION_OLD_NEXT_ID <> SESSION_NEXT_ID ) {
$SQL->addUpdate('session_id', SESSION_OLD_NEXT_ID);
$SQL->addUpdate('session_next_id', SESSION_NEXT_ID);
}
$SQL->addWhereOpr('session_id', SID);
$DB->query($SQL->get(dsn()), 'exec');
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment