diff --git a/lib/read_db_cache.php b/lib/read_db_cache.php index d67fc48..6f58a99 100644 --- a/lib/read_db_cache.php +++ b/lib/read_db_cache.php @@ -82,21 +82,30 @@ function qdb_read_materialize_decrypted_db(): array { $memfd = qdb_memfd_write($decrypted); if ($memfd !== null) { [$fd, $path] = $memfd; - $pdo = qdb_read_open_sqlite_on_path($path, $sql, false); - return [$pdo, $path, $fd]; + try { + $pdo = qdb_read_open_sqlite_on_path($path, $sql, false); + return [$pdo, $path, $fd]; + } catch (Throwable $e) { + // memfd is filled but SQLite cannot open /proc/self/fd on this host. + qdb_close_fd($fd); + } } - $fallbackDir = QDB_UPLOADS_DIR . '/.private_read'; - if (!is_dir($fallbackDir)) { - @mkdir($fallbackDir, 0700, true); + $snapshotPath = qdb_read_ram_snapshot_path(); + if (file_put_contents($snapshotPath, $decrypted) === false) { + throw new Exception('Could not write read snapshot'); } - $fallback = $fallbackDir . '/snap_' . getmypid() . '_' . bin2hex(random_bytes(4)) . '.sqlite'; - if (file_put_contents($fallback, $decrypted) === false) { - throw new Exception('Could not write private read snapshot'); - } - @chmod($fallback, 0600); - $pdo = qdb_read_open_sqlite_on_path($fallback, $sql, false); - return [$pdo, $fallback, -1]; + @chmod($snapshotPath, 0600); + $pdo = qdb_read_open_sqlite_on_path($snapshotPath, $sql, false); + return [$pdo, $snapshotPath, -1]; +} + +/** + * RAM-backed snapshot path (tmpfs). One file per worker; overwritten on refresh. + */ +function qdb_read_ram_snapshot_path(): string { + $dir = is_writable('/dev/shm') ? '/dev/shm' : sys_get_temp_dir(); + return $dir . '/qdb_read_' . getmypid() . '.sqlite'; } /** @@ -223,6 +232,8 @@ function qdb_read_open_sqlite_on_path(string $sqlitePath, string $schemaSql, boo if ($bytes === false || file_put_contents($savePath, $bytes) === false) { throw new Exception('Could not copy memfd DB for migration save'); } + } elseif (!is_file($savePath)) { + throw new Exception('Cannot persist migration from missing read snapshot'); } $pdo->exec('PRAGMA wal_checkpoint(FULL);'); qdb_save($savePath, $migrateLock);