@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
at upstream/main 103 lines 2.7 kB view raw
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}