PluginProbe
404 Solution / 4.3.3
404 Solution v4.3.3
4.3.5 4.3.4 4.3.3 4.3.2 4.3.1 4.3.0 4.2.0 4.1.19 4.1.18 4.1.17 4.1.16 4.1.15 4.1.13 4.1.12 4.1.11 4.1.10 4.1.9 4.1.8 4.1.7 4.1.6 4.1.5 4.1.4 4.1.3 trunk 2.30.0 All 109 releases
404-solution / includes / database / DatabaseHostStateErrorTaxonomy.php

DatabaseHostStateErrorTaxonomy.php in 404 Solution 4.3.3, at includes/database/DatabaseHostStateErrorTaxonomy.php

149 lines 5.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Pure database host-state error taxonomy.
4 *
5 * Owns string-based classification of server-side state failures: storage
6 * exhaustion (disk, quota, memory), write-blocking modes (read-only,
7 * Galera cluster-readiness and optimistic-concurrency conflicts), and
8 * access-control rejections (access denied, missing SUPER privilege for SET
9 * STATEMENT). These are the error classes the notice-state side-effects and
10 * "permanent host-side staged failure" policies act on.
11 *
12 * No side effects: callers reuse the matchers without inheriting recovery
13 * behavior.
14 */
15
16 if (!defined('ABSPATH')) {
17 exit;
18 }
19
20 // allow-no-test-found: covered through DatabaseInfrastructureErrorTaxonomy facade by tests/ErrorClassifierTest.php and tests/StagedBuildHostQuirksTest.php
21 class ABJ_404_Solution_DatabaseHostStateErrorTaxonomy {
22
23 /**
24 * Galera conditions where the same query can succeed after cluster state
25 * or optimistic certification advances. This data table is the single
26 * vocabulary for both warning severity and DAO retry policy.
27 *
28 * @var array<int, string>
29 */
30 private const RETRYABLE_GALERA_MARKERS = array(
31 'record has changed since last read',
32 'wsrep_local_state',
33 'cluster conflict',
34 'wsrep has not yet prepared node for application use',
35 'node is not ready for application use',
36 'non-primary component',
37 'non primary component',
38 );
39
40 /** @var ABJ_404_Solution_Functions */
41 private $f;
42
43 /**
44 * @param ABJ_404_Solution_Functions $functions
45 */
46 public function __construct($functions) {
47 $this->f = $functions;
48 }
49
50 /** @param string $errorText @return bool */
51 public function isDiskFullError(string $errorText): bool {
52 if ($errorText === '') {
53 return false;
54 }
55 $lower = strtolower($errorText);
56 return ($this->f->strpos($lower, 'error 28') !== false ||
57 $this->f->strpos($lower, 'errno: 28') !== false ||
58 $this->f->strpos($lower, 'errcode: 28') !== false ||
59 $this->f->strpos($lower, 'no space left on device') !== false ||
60 $this->f->strpos($lower, 'disk quota exceeded') !== false ||
61 $this->f->strpos($lower, "' is full") !== false ||
62 $this->f->strpos($lower, 'table is full') !== false ||
63 $this->f->strpos($lower, 'disk full') !== false);
64 }
65
66 /** @param string $errorText @return bool */
67 public function isReadOnlyError(string $errorText): bool {
68 if ($errorText === '') {
69 return false;
70 }
71 $lower = strtolower($errorText);
72 return ($this->f->strpos($lower, 'read only') !== false ||
73 $this->f->strpos($lower, 'read-only') !== false ||
74 $this->f->strpos($lower, 'super_read_only') !== false);
75 }
76
77 /** @param string $errorText @return bool */
78 public function isQuotaLimitError(string $errorText): bool {
79 if ($errorText === '') {
80 return false;
81 }
82 $lower = strtolower($errorText);
83 return ($this->f->strpos($lower, 'max_questions') !== false ||
84 $this->f->strpos($lower, 'resource') !== false && $this->f->strpos($lower, 'question') !== false);
85 }
86
87 /** @param string $errorText @return bool */
88 public function isAccessDeniedError(string $errorText): bool {
89 if ($errorText === '') {
90 return false;
91 }
92 $lower = strtolower($errorText);
93 return ($this->f->strpos($lower, 'access denied') !== false ||
94 $this->f->strpos($lower, 'command denied') !== false);
95 }
96
97 /** @param string $errorText @return bool */
98 public function isOutOfMemoryError(string $errorText): bool {
99 if ($errorText === '') {
100 return false;
101 }
102 $lower = strtolower($errorText);
103 return ($this->f->strpos($lower, 'allowed memory size') !== false ||
104 $this->f->strpos($lower, 'out of memory') !== false ||
105 $this->f->strpos($lower, 'memory exhausted') !== false ||
106 $this->f->strpos($lower, 'memory_limit') !== false);
107 }
108
109 /** @param string $errorText @return bool */
110 public function isGaleraConflictError(string $errorText): bool {
111 if ($errorText === '') {
112 return false;
113 }
114 $lower = strtolower($errorText);
115 foreach (self::RETRYABLE_GALERA_MARKERS as $marker) {
116 if ($this->f->strpos($lower, $marker) !== false) {
117 return true;
118 }
119 }
120 return false;
121 }
122
123 /**
124 * True when a failed SET STATEMENT max_statement_time wrapper can be
125 * stripped and retried.
126 *
127 * @param string $errorText
128 * @return bool
129 */
130 public function classifySetStatementFailure(string $errorText): bool {
131 if ($errorText === '') {
132 return false;
133 }
134 $lower = strtolower($errorText);
135 if ($this->f->strpos($lower, 'super privilege') !== false ||
136 $this->f->strpos($lower, 'super_privilege') !== false ||
137 $this->f->strpos($lower, '(at least one of) the super') !== false) {
138 return true;
139 }
140 if (($this->f->strpos($lower, 'syntax error') !== false ||
141 $this->f->strpos($lower, 'error in your sql syntax') !== false ||
142 $this->f->strpos($lower, '1064') !== false) &&
143 $this->f->strpos($lower, 'set statement') !== false) {
144 return true;
145 }
146 return false;
147 }
148 }
149