Skip to content

update-from-1-7 crashes while clearing a SQLite cache #1964

Description

@TheBearBoB

Summary

When Providence 2.0.11 is configured with the SQLite cache backend, caUtils update-from-1-7 crashes during Step 1 of 9, Clearing caches, with:

PDOException: SQLSTATE[HY000]: General error: 8 attempt to write a readonly database

The failure was reproduced using the official Providence 2.0.11 release. Filesystem permissions, ownership, ACLs, filesystem attributes, and SQLite read-only mode were checked and do not account for the error.

Environment

  • Source installation: Providence 1.7.11
  • Source database revision: 158
  • Target: official Providence 2.0.11 release ZIP
  • PHP CLI: 8.4
  • OS: Rocky Linux 8
  • Database: MariaDB 10.6
  • Test context: isolated staging clone; production was unchanged

Configuration

define('__CA_CACHE_BACKEND__', 'sqlite');

The cache and temporary directory both resolve to app/tmp. The SQLite cache file resolves beneath:

app/tmp/collectiveaccessCache/cache.sqlite

Steps to reproduce

From the Providence 2.0.11 application directory:

php support/bin/caUtils update-from-1-7

Confirm the prompt to update the 1.7 database. The command begins Step 1, starts clearing application caches, and terminates with the SQLite exception before any MariaDB schema migration step is reached.

Expected behavior

The updater should clear every supported cache backend and continue to the database migration steps.

Actual behavior

The updater terminates in Stash\Driver\Sub\SqlitePdo::set() while application caches are being cleared. The representative call path is:

Stash\Driver\Sub\SqlitePdo->set()
Stash\Driver\Sqlite->storeData()
Stash\Item->executeSet()
Stash\Pool->save()
ExternalCache::save()
Configuration->__destruct()
MemoryCache::flush()
CLIUtils::clear_caches()
CLIUtils::update_from_1_7()

Reported source locations in the 2.0.11 package include:

vendor/tedivm/stash/src/Stash/Driver/Sub/SqlitePdo.php:152
app/lib/Cache/ExternalCache.php:159
app/lib/Configuration.php:1129
app/lib/Cache/MemoryCache.php:132
app/lib/Utils/CLIUtils/Maintenance.php:1080
app/lib/Utils/CLIUtils/Migration.php:61
support/bin/caUtils:180

Evidence against a permissions cause

  • The effective PHP CLI user owns the cache file and parent directory.
  • PHP reports both the SQLite file and cache directory as writable.
  • The directory mode is 775; the SQLite file mode is 660.
  • ACLs contain no restrictive entries.
  • No immutable or append-only filesystem attributes are set.
  • SQLite PRAGMA query_only is 0.
  • SQLite PRAGMA journal_mode is delete.
  • SQLite PRAGMA locking_mode is normal.

Relevant source path

The 2.0.11 migration invokes CLIUtils::clear_caches() at the beginning of Step 1:

CLIUtils::clear_caches();

Source: Migration.php lines 56-62

The application-cache branch performs a full external-cache flush, followed by a memory-cache flush:

ExternalCache::flush();
MemoryCache::flush();

Source: Maintenance.php lines 1056-1081

For a full external-cache flush, Providence calls clear() on the existing static Stash pool but retains that pool in ExternalCache::$cache:

self::getCache()->clear();

Source: ExternalCache.php lines 200-208

Providence 2.0.11 locks tedivm/stash v1.2.2 at commit 39c426e. Its SQLite full-clear path closes the driver and deletes the SQLite file:

$this->driver = null;
$this->driver = false;
\Stash\Utilities::deleteRecursive($this->path);

Sources:

The observed call stack then reaches the configuration destructor, which writes cached configuration values through ExternalCache::save():

foreach(self::$s_config_cache as $k => $v) {
	ExternalCache::save($k, $v, 'ConfigurationCache', 3600 * 3600 * 30);
}

Source: Configuration.php lines 1124-1132

Source analysis

The observed behavior and call path suggest a cache-lifecycle interaction: a full SQLite clear deletes the backing database, but a configuration destructor attempts another cache write during the same clear operation. I have not tested a code patch, so I cannot determine whether the safest correction belongs in Providence's pool lifecycle, its configuration-cache write lifecycle, or the bundled Stash driver.

Impact

  • A 1.7-to-2.0 migration cannot proceed with this cache configuration.
  • The exception resembles an ordinary permissions problem and can lead to unnecessary server changes.
  • The failure occurs before the application database is migrated.

Confirmed workaround

Changing only the staging cache backend from sqlite to file, then moving the failed SQLite cache directory aside, allowed cache clearing and the migration to proceed. This was a staging-only workaround.

Possible implementation direction

One candidate would be to discard the retained static pool after a successful full clear, allowing the next cache access to initialize a new pool and SQLite driver:

self::getCache()->clear();
self::$cache = null;

That would be a small change in the full-clear branch of ExternalCache::flush(), but it is only a proposed direction. Maintainers may prefer to suppress configuration-cache writes during clearing or explicitly reinitialize the pool elsewhere in the lifecycle.

A regression test could configure __CA_CACHE_BACKEND__ = 'sqlite', populate the configuration cache, perform a full cache clear, release cached configuration objects, and then verify that a new cache write succeeds. An end-to-end update-from-1-7 test using SQLite caching would cover the reported path directly.

AI assistance disclosure

This report was developed with ChatGPT Work using GPT-5.6 Sol with Extra High reasoning for source review, troubleshooting support, and drafting. Runtime claims, where included, were reproduced on an isolated staging clone; source-level claims were checked against the official Providence 2.0.11 release code.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions