-
-
Notifications
You must be signed in to change notification settings - Fork 43
Expand file tree
/
Copy pathSQLiteJournal.php
More file actions
145 lines (112 loc) · 3.36 KB
/
SQLiteJournal.php
File metadata and controls
145 lines (112 loc) · 3.36 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
<?php
/**
* This file is part of the Nette Framework (https://nette.org)
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
*/
declare(strict_types=1);
namespace Nette\Caching\Storages;
use Nette;
use Nette\Caching\Cache;
use function count, extension_loaded, implode, is_file, str_repeat, touch;
/**
* SQLite based journal.
*/
class SQLiteJournal implements Journal
{
/** @string */
private $path;
private \PDO $pdo;
public function __construct(string $path)
{
if (!extension_loaded('pdo_sqlite')) {
throw new Nette\NotSupportedException('SQLiteJournal requires PHP extension pdo_sqlite which is not loaded.');
}
$this->path = $path;
}
private function open(): void
{
if ($this->path !== ':memory:' && !is_file($this->path)) {
touch($this->path); // ensures ordinary file permissions
}
$this->pdo = new \PDO('sqlite:' . $this->path);
$this->pdo->exec('
PRAGMA foreign_keys = OFF;
PRAGMA journal_mode = WAL;
CREATE TABLE IF NOT EXISTS tags (
key BLOB NOT NULL,
tag BLOB NOT NULL
);
CREATE TABLE IF NOT EXISTS priorities (
key BLOB NOT NULL,
priority INT NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_tags_tag ON tags(tag);
CREATE UNIQUE INDEX IF NOT EXISTS idx_tags_key_tag ON tags(key, tag);
CREATE UNIQUE INDEX IF NOT EXISTS idx_priorities_key ON priorities(key);
CREATE INDEX IF NOT EXISTS idx_priorities_priority ON priorities(priority);
PRAGMA synchronous = NORMAL;
');
}
public function write(string $key, array $dependencies): void
{
if (!isset($this->pdo)) {
$this->open();
}
$this->pdo->exec('BEGIN');
if (!empty($dependencies[Cache::Tags])) {
$this->pdo->prepare('DELETE FROM tags WHERE key = ?')->execute([$key]);
foreach ($dependencies[Cache::Tags] as $tag) {
$arr[] = $key;
$arr[] = $tag;
}
$this->pdo->prepare('INSERT INTO tags (key, tag) SELECT ?, ?' . str_repeat('UNION SELECT ?, ?', count($arr) / 2 - 1))
->execute($arr);
}
if (!empty($dependencies[Cache::Priority])) {
$this->pdo->prepare('REPLACE INTO priorities (key, priority) VALUES (?, ?)')
->execute([$key, (int) $dependencies[Cache::Priority]]);
}
$this->pdo->exec('COMMIT');
}
public function clean(array $conditions): ?array
{
if (!isset($this->pdo)) {
$this->open();
}
if (!empty($conditions[Cache::All])) {
$this->pdo->exec('
BEGIN;
DELETE FROM tags;
DELETE FROM priorities;
COMMIT;
');
return null;
}
$unions = $args = [];
if (!empty($conditions[Cache::Tags])) {
$tags = (array) $conditions[Cache::Tags];
$unions[] = 'SELECT DISTINCT key FROM tags WHERE tag IN (?' . str_repeat(', ?', count($tags) - 1) . ')';
$args = $tags;
}
if (!empty($conditions[Cache::Priority])) {
$unions[] = 'SELECT DISTINCT key FROM priorities WHERE priority <= ?';
$args[] = (int) $conditions[Cache::Priority];
}
if (empty($unions)) {
return [];
}
$unionSql = implode(' UNION ', $unions);
$this->pdo->exec('BEGIN IMMEDIATE');
$stmt = $this->pdo->prepare($unionSql);
$stmt->execute($args);
$keys = $stmt->fetchAll(\PDO::FETCH_COLUMN, 0);
if (empty($keys)) {
$this->pdo->exec('COMMIT');
return [];
}
$this->pdo->prepare("DELETE FROM tags WHERE key IN ($unionSql)")->execute($args);
$this->pdo->prepare("DELETE FROM priorities WHERE key IN ($unionSql)")->execute($args);
$this->pdo->exec('COMMIT');
return $keys;
}
}