@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.)
hq.recaptime.dev/wiki/Phorge
phorge
phabricator
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 */
29final 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->canResolve()) {
55 return true;
56 }
57
58 if (!$this->async) {
59 $profiler = PhutilServiceProfiler::getInstance();
60 $this->profilerCallID = $profiler->beginServiceCall(
61 array(
62 'type' => 'query',
63 'query' => $this->query,
64 'async' => true,
65 ));
66
67 $this->async = $this->conn->asyncQuery($this->query);
68 return false;
69 }
70
71 $conns = array();
72 $asyncs = array();
73 foreach (self::$futures as $id => $future) {
74 if ($future->async) {
75 $conns[$id] = $future->conn;
76 $asyncs[$id] = $future->async;
77 }
78 }
79
80 $this->processResults($this->conn->resolveAsyncQueries($conns, $asyncs));
81
82 if ($this->canResolve()) {
83 return true;
84 }
85 return false;
86 }
87
88 private function processResults(array $results) {
89 foreach ($results as $id => $result) {
90 $future = self::$futures[$id];
91 if ($result instanceof Exception) {
92 $future->exception = $result;
93 } else {
94 $future->result = $result;
95 }
96 unset(self::$futures[$id]);
97 if ($future->profilerCallID) {
98 $profiler = PhutilServiceProfiler::getInstance();
99 $profiler->endServiceCall($future->profilerCallID, array());
100 }
101 }
102 }
103}