Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/src/infrastructure/storage/future/QueryFuture.php
12241 views
1
<?php
2
3
/**
4
* This class provides several approaches for querying data from the database:
5
*
6
* # Async queries: Used under MySQLi with MySQLnd.
7
* # Parallel queries: Used under HPHP.
8
* # Multi queries: Used under MySQLi or HPHP.
9
* # Single queries: Used under MySQL.
10
*
11
* The class automatically decides which approach to use. Usage is like with
12
* other futures:
13
*
14
* $futures = array();
15
* $futures[] = new QueryFuture($conn1, 'SELECT 1');
16
* $futures[] = new QueryFuture($conn1, 'DELETE FROM table');
17
* $futures[] = new QueryFuture($conn2, 'SELECT 2');
18
*
19
* foreach (new FutureIterator($futures) as $future) {
20
* try {
21
* $result = $future->resolve();
22
* } catch (AphrontQueryException $ex) {
23
* }
24
* }
25
*
26
* `$result` contains a list of dicts for select queries or number of modified
27
* rows for modification queries.
28
*/
29
final class QueryFuture extends Future {
30
31
private static $futures = array();
32
33
private $conn;
34
private $query;
35
private $id;
36
private $async;
37
private $profilerCallID;
38
39
public function __construct(
40
AphrontDatabaseConnection $conn,
41
$pattern/* , ... */) {
42
43
$this->conn = $conn;
44
45
$args = func_get_args();
46
$args = array_slice($args, 2);
47
$this->query = vqsprintf($conn, $pattern, $args);
48
49
self::$futures[] = $this;
50
$this->id = last_key(self::$futures);
51
}
52
53
public function isReady() {
54
if ($this->result !== null || $this->exception) {
55
return true;
56
}
57
58
if (!$this->conn->supportsAsyncQueries()) {
59
if ($this->conn->supportsParallelQueries()) {
60
$queries = array();
61
$conns = array();
62
foreach (self::$futures as $id => $future) {
63
$queries[$id] = $future->query;
64
$conns[$id] = $future->conn;
65
}
66
$results = $this->conn->executeParallelQueries($queries, $conns);
67
$this->processResults($results);
68
return true;
69
}
70
71
$conns = array();
72
$conn_queries = array();
73
foreach (self::$futures as $id => $future) {
74
$hash = spl_object_hash($future->conn);
75
$conns[$hash] = $future->conn;
76
$conn_queries[$hash][$id] = $future->query;
77
}
78
foreach ($conn_queries as $hash => $queries) {
79
$this->processResults($conns[$hash]->executeRawQueries($queries));
80
}
81
return true;
82
}
83
84
if (!$this->async) {
85
$profiler = PhutilServiceProfiler::getInstance();
86
$this->profilerCallID = $profiler->beginServiceCall(
87
array(
88
'type' => 'query',
89
'query' => $this->query,
90
'async' => true,
91
));
92
93
$this->async = $this->conn->asyncQuery($this->query);
94
return false;
95
}
96
97
$conns = array();
98
$asyncs = array();
99
foreach (self::$futures as $id => $future) {
100
if ($future->async) {
101
$conns[$id] = $future->conn;
102
$asyncs[$id] = $future->async;
103
}
104
}
105
106
$this->processResults($this->conn->resolveAsyncQueries($conns, $asyncs));
107
108
if ($this->result !== null || $this->exception) {
109
return true;
110
}
111
return false;
112
}
113
114
private function processResults(array $results) {
115
foreach ($results as $id => $result) {
116
$future = self::$futures[$id];
117
if ($result instanceof Exception) {
118
$future->exception = $result;
119
} else {
120
$future->result = $result;
121
}
122
unset(self::$futures[$id]);
123
if ($future->profilerCallID) {
124
$profiler = PhutilServiceProfiler::getInstance();
125
$profiler->endServiceCall($future->profilerCallID, array());
126
}
127
}
128
}
129
}
130
131