상태 캐시 의미 테이블 전환

This commit is contained in:
seo
2026-07-23 02:41:25 +09:00
parent 1947b31c87
commit a473e70dfc
3 changed files with 237 additions and 109 deletions
+138 -98
View File
@@ -121,70 +121,8 @@ function dmesg_log(): array
];
}
function json_store_key_from_path(string $path): string
function power_event_state_read(string $eventKey): array
{
$name = preg_replace('/[^a-zA-Z0-9_.-]+/', '-', basename($path, '.json')) ?: md5($path);
return 'file:' . $name;
}
function json_store_read(string $key, ?string $legacyPath = null): ?array
{
try {
$stmt = db()->prepare("
SELECT payload, expires_at
FROM app_json_store
WHERE store_key = :store_key
AND (expires_at IS NULL OR expires_at >= NOW())
LIMIT 1
");
$stmt->execute([':store_key' => $key]);
$row = $stmt->fetch();
if ($row) {
$decoded = json_decode((string)$row['payload'], true);
if (is_array($decoded)) {
return $decoded;
}
}
} catch (Throwable) {
}
if ($legacyPath !== null && is_readable($legacyPath)) {
$decoded = json_decode((string)@file_get_contents($legacyPath), true);
if (is_array($decoded)) {
json_store_write($key, $decoded);
return $decoded;
}
}
return null;
}
function json_store_write(string $key, array $payload, ?int $ttlSeconds = null): void
{
$expiresAt = $ttlSeconds !== null ? date('Y-m-d H:i:s', time() + max(1, $ttlSeconds)) : null;
$stmt = db()->prepare("
INSERT INTO app_json_store (store_key, payload, expires_at)
VALUES (:store_key, :payload, :expires_at)
ON DUPLICATE KEY UPDATE
payload = VALUES(payload),
expires_at = VALUES(expires_at),
updated_at = CURRENT_TIMESTAMP
");
$stmt->execute([
':store_key' => $key,
':payload' => json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
':expires_at' => $expiresAt,
]);
}
function throttled_event_status(?int $flags, string $raw, int $activeBit, int $seenBit, string $statePath): array
{
$now = time();
$windowSeconds = (int)setting_value('event.recent_window_seconds');
$recoverySeconds = (int)setting_value('event.recovery_seconds');
$active = $flags !== null && (bool)($flags & $activeBit);
$seen = $flags !== null && (bool)($flags & $seenBit);
$state = [
'active' => false,
'active_since' => null,
@@ -195,11 +133,69 @@ function throttled_event_status(?int $flags, string $raw, int $activeBit, int $s
'events' => [],
];
$stmt = db()->prepare("
SELECT *
FROM power_event_states
WHERE event_key = :event_key
LIMIT 1
");
$stmt->execute([':event_key' => $eventKey]);
$row = $stmt->fetch();
if (!$row) {
return $state;
}
$events = json_decode((string)($row['event_history'] ?? '[]'), true);
$state['active'] = (bool)($row['active'] ?? false);
$state['active_since'] = is_numeric($row['active_since'] ?? null) ? (int)$row['active_since'] : null;
$state['last_detected_at'] = is_numeric($row['last_detected_at'] ?? null) ? (int)$row['last_detected_at'] : null;
$state['last_cleared_at'] = is_numeric($row['last_cleared_at'] ?? null) ? (int)$row['last_cleared_at'] : null;
$state['last_duration_seconds'] = (int)($row['last_duration_seconds'] ?? 0);
$state['updated_at'] = is_numeric($row['refreshed_at'] ?? null) ? (int)$row['refreshed_at'] : null;
$state['events'] = is_array($events) ? $events : [];
return $state;
}
function power_event_state_write(string $eventKey, array $state): void
{
$stmt = db()->prepare("
INSERT INTO power_event_states
(event_key, active, active_since, last_detected_at, last_cleared_at, last_duration_seconds, event_history, refreshed_at)
VALUES
(:event_key, :active, :active_since, :last_detected_at, :last_cleared_at, :last_duration_seconds, :event_history, :refreshed_at)
ON DUPLICATE KEY UPDATE
active = VALUES(active),
active_since = VALUES(active_since),
last_detected_at = VALUES(last_detected_at),
last_cleared_at = VALUES(last_cleared_at),
last_duration_seconds = VALUES(last_duration_seconds),
event_history = VALUES(event_history),
refreshed_at = VALUES(refreshed_at),
updated_at = CURRENT_TIMESTAMP
");
$stmt->execute([
':event_key' => $eventKey,
':active' => !empty($state['active']) ? 1 : 0,
':active_since' => is_numeric($state['active_since'] ?? null) ? (int)$state['active_since'] : null,
':last_detected_at' => is_numeric($state['last_detected_at'] ?? null) ? (int)$state['last_detected_at'] : null,
':last_cleared_at' => is_numeric($state['last_cleared_at'] ?? null) ? (int)$state['last_cleared_at'] : null,
':last_duration_seconds' => (int)($state['last_duration_seconds'] ?? 0),
':event_history' => json_encode($state['events'] ?? [], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
':refreshed_at' => is_numeric($state['updated_at'] ?? null) ? (int)$state['updated_at'] : time(),
]);
}
function throttled_event_status(?int $flags, string $raw, int $activeBit, int $seenBit, string $eventKey): array
{
$now = time();
$windowSeconds = (int)setting_value('event.recent_window_seconds');
$recoverySeconds = (int)setting_value('event.recovery_seconds');
$active = $flags !== null && (bool)($flags & $activeBit);
$seen = $flags !== null && (bool)($flags & $seenBit);
try {
$decoded = json_store_read(json_store_key_from_path($statePath), $statePath);
if (is_array($decoded)) {
$state = array_merge($state, array_intersect_key($decoded, $state));
}
$state = power_event_state_read($eventKey);
$state['events'] = array_values(array_filter(
is_array($state['events'] ?? null) ? $state['events'] : [],
static fn($event): bool => is_array($event) && is_numeric($event['start'] ?? null)
@@ -252,9 +248,18 @@ function throttled_event_status(?int $flags, string $raw, int $activeBit, int $s
)), -200);
$state['updated_at'] = $now;
json_store_write(json_store_key_from_path($statePath), $state);
power_event_state_write($eventKey, $state);
}
} catch (Throwable) {
$state = [
'active' => false,
'active_since' => null,
'last_detected_at' => null,
'last_cleared_at' => null,
'last_duration_seconds' => 0,
'updated_at' => null,
'events' => [],
];
}
$duration = 0;
@@ -361,8 +366,8 @@ function throttled_statuses(): array
$flags = $read['flags'];
$source = (string)$read['source'];
$lowVoltage = throttled_event_status($flags, $raw, 0x1, 0x10000, '/tmp/control-low-voltage-state.json');
$throttling = throttled_event_status($flags, $raw, 0x4, 0x40000, '/tmp/control-throttling-state.json');
$lowVoltage = throttled_event_status($flags, $raw, 0x1, 0x10000, 'low_voltage');
$throttling = throttled_event_status($flags, $raw, 0x4, 0x40000, 'throttling');
$lowVoltage['source'] = $source;
$lowVoltage['freq_capped'] = $flags !== null && (bool)($flags & 0x2);
@@ -927,8 +932,6 @@ function battery_profile_history(int $days = 45): array
static $cache = [];
$cacheKey = (string)$days;
$now = time();
$storeKey = 'battery_profile:' . $days . 'd';
$legacyCacheFile = sys_get_temp_dir() . '/control-battery-profile-' . $days . 'd.json';
if (
isset($cache[$cacheKey])
@@ -938,18 +941,24 @@ function battery_profile_history(int $days = 45): array
return $cache[$cacheKey]['rows'];
}
$decoded = json_store_read($storeKey, $legacyCacheFile);
if (
is_array($decoded)
&& isset($decoded['created_at'], $decoded['rows'])
&& is_array($decoded['rows'])
&& ($now - (int)$decoded['created_at']) < 21600
) {
$cache[$cacheKey] = [
'time' => $now,
'rows' => $decoded['rows'],
];
return $decoded['rows'];
$stmt = db()->prepare("
SELECT created_at_epoch, sample_rows
FROM battery_profile_cache
WHERE days = :days
AND expires_at >= NOW()
LIMIT 1
");
$stmt->execute([':days' => $days]);
$cached = $stmt->fetch();
if ($cached) {
$rows = json_decode((string)$cached['sample_rows'], true);
if (is_array($rows)) {
$cache[$cacheKey] = [
'time' => $now,
'rows' => $rows,
];
return $rows;
}
}
$maxId = (int)db()->query("SELECT MAX(id) FROM sensor_logs")->fetchColumn();
@@ -992,11 +1001,22 @@ function battery_profile_history(int $days = 45): array
'time' => $now,
'rows' => $rows,
];
json_store_write($storeKey, [
'created_at' => $now,
'days' => $days,
'rows' => $rows,
], 21600);
$stmt = db()->prepare("
INSERT INTO battery_profile_cache
(days, created_at_epoch, sample_rows, expires_at)
VALUES
(:days, :created_at_epoch, :sample_rows, DATE_ADD(NOW(), INTERVAL 6 HOUR))
ON DUPLICATE KEY UPDATE
created_at_epoch = VALUES(created_at_epoch),
sample_rows = VALUES(sample_rows),
expires_at = VALUES(expires_at),
updated_at = CURRENT_TIMESTAMP
");
$stmt->execute([
':days' => $days,
':created_at_epoch' => $now,
':sample_rows' => json_encode($rows, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
]);
return $rows;
}
@@ -3443,11 +3463,19 @@ function systemd_service_logs(string $unit, int $limit = 12): array
function custom_systemd_services(): array
{
$cacheSeconds = (int)setting_value('display.custom_service_cache_seconds');
$cacheKey = 'custom_services';
$cached = json_store_read($cacheKey, '/tmp/control-custom-services.json');
if (is_array($cached) && isset($cached['created_at'], $cached['rows']) && is_array($cached['rows'])) {
if (time() - (int)$cached['created_at'] <= $cacheSeconds) {
return $cached['rows'];
$stmt = db()->prepare("
SELECT service_rows
FROM systemd_service_cache
WHERE cache_key = 1
AND expires_at >= NOW()
LIMIT 1
");
$stmt->execute();
$cached = $stmt->fetch();
if ($cached) {
$rows = json_decode((string)$cached['service_rows'], true);
if (is_array($rows)) {
return $rows;
}
}
@@ -3510,10 +3538,22 @@ function custom_systemd_services(): array
];
}
json_store_write($cacheKey, [
'created_at' => time(),
'rows' => $rows,
], $cacheSeconds);
$stmt = db()->prepare("
INSERT INTO systemd_service_cache
(cache_key, captured_at, service_rows, expires_at)
VALUES
(1, :captured_at, :service_rows, :expires_at)
ON DUPLICATE KEY UPDATE
captured_at = VALUES(captured_at),
service_rows = VALUES(service_rows),
expires_at = VALUES(expires_at),
updated_at = CURRENT_TIMESTAMP
");
$stmt->execute([
':captured_at' => time(),
':service_rows' => json_encode($rows, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
':expires_at' => date('Y-m-d H:i:s', time() + max(1, $cacheSeconds)),
]);
return $rows;
}