Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/src/applications/fact/daemon/PhabricatorFactDaemon.php
12256 views
1
<?php
2
3
final class PhabricatorFactDaemon extends PhabricatorDaemon {
4
5
private $engines;
6
7
protected function run() {
8
$this->setEngines(PhabricatorFactEngine::loadAllEngines());
9
do {
10
PhabricatorCaches::destroyRequestCache();
11
12
$iterators = $this->getAllApplicationIterators();
13
foreach ($iterators as $iterator_name => $iterator) {
14
$this->processIteratorWithCursor($iterator_name, $iterator);
15
}
16
17
$sleep_duration = 60;
18
19
if ($this->shouldHibernate($sleep_duration)) {
20
break;
21
}
22
23
$this->sleep($sleep_duration);
24
} while (!$this->shouldExit());
25
}
26
27
public static function getAllApplicationIterators() {
28
$apps = PhabricatorApplication::getAllInstalledApplications();
29
30
$iterators = array();
31
foreach ($apps as $app) {
32
foreach ($app->getFactObjectsForAnalysis() as $object) {
33
$iterator = new PhabricatorFactUpdateIterator($object);
34
$iterators[get_class($object)] = $iterator;
35
}
36
}
37
38
return $iterators;
39
}
40
41
public function processIteratorWithCursor($iterator_name, $iterator) {
42
$this->log(pht("Processing cursor '%s'.", $iterator_name));
43
44
$cursor = id(new PhabricatorFactCursor())->loadOneWhere(
45
'name = %s',
46
$iterator_name);
47
if (!$cursor) {
48
$cursor = new PhabricatorFactCursor();
49
$cursor->setName($iterator_name);
50
$position = null;
51
} else {
52
$position = $cursor->getPosition();
53
}
54
55
if ($position) {
56
$iterator->setPosition($position);
57
}
58
59
$new_cursor_position = $this->processIterator($iterator);
60
61
if ($new_cursor_position) {
62
$cursor->setPosition($new_cursor_position);
63
$cursor->save();
64
}
65
}
66
67
public function setEngines(array $engines) {
68
assert_instances_of($engines, 'PhabricatorFactEngine');
69
70
$viewer = PhabricatorUser::getOmnipotentUser();
71
foreach ($engines as $engine) {
72
$engine->setViewer($viewer);
73
}
74
75
$this->engines = $engines;
76
return $this;
77
}
78
79
public function processIterator($iterator) {
80
$result = null;
81
82
$datapoints = array();
83
$count = 0;
84
foreach ($iterator as $key => $object) {
85
$phid = $object->getPHID();
86
$this->log(pht('Processing %s...', $phid));
87
$object_datapoints = $this->newDatapoints($object);
88
$count += count($object_datapoints);
89
90
$datapoints[$phid] = $object_datapoints;
91
92
if ($count > 1024) {
93
$this->updateDatapoints($datapoints);
94
$datapoints = array();
95
$count = 0;
96
}
97
98
$result = $key;
99
}
100
101
if ($count) {
102
$this->updateDatapoints($datapoints);
103
$datapoints = array();
104
$count = 0;
105
}
106
107
return $result;
108
}
109
110
private function newDatapoints(PhabricatorLiskDAO $object) {
111
$facts = array();
112
foreach ($this->engines as $engine) {
113
if (!$engine->supportsDatapointsForObject($object)) {
114
continue;
115
}
116
$facts[] = $engine->newDatapointsForObject($object);
117
}
118
119
return array_mergev($facts);
120
}
121
122
private function updateDatapoints(array $map) {
123
foreach ($map as $phid => $facts) {
124
assert_instances_of($facts, 'PhabricatorFactIntDatapoint');
125
}
126
127
$phids = array_keys($map);
128
if (!$phids) {
129
return;
130
}
131
132
$fact_keys = array();
133
$objects = array();
134
foreach ($map as $phid => $facts) {
135
foreach ($facts as $fact) {
136
$fact_keys[$fact->getKey()] = true;
137
138
$object_phid = $fact->getObjectPHID();
139
$objects[$object_phid] = $object_phid;
140
141
$dimension_phid = $fact->getDimensionPHID();
142
if ($dimension_phid !== null) {
143
$objects[$dimension_phid] = $dimension_phid;
144
}
145
}
146
}
147
148
$key_map = id(new PhabricatorFactKeyDimension())
149
->newDimensionMap(array_keys($fact_keys), true);
150
$object_map = id(new PhabricatorFactObjectDimension())
151
->newDimensionMap(array_keys($objects), true);
152
153
$table = new PhabricatorFactIntDatapoint();
154
$conn = $table->establishConnection('w');
155
$table_name = $table->getTableName();
156
157
$sql = array();
158
foreach ($map as $phid => $facts) {
159
foreach ($facts as $fact) {
160
$key_id = $key_map[$fact->getKey()];
161
$object_id = $object_map[$fact->getObjectPHID()];
162
163
$dimension_phid = $fact->getDimensionPHID();
164
if ($dimension_phid !== null) {
165
$dimension_id = $object_map[$dimension_phid];
166
} else {
167
$dimension_id = null;
168
}
169
170
$sql[] = qsprintf(
171
$conn,
172
'(%d, %d, %nd, %d, %d)',
173
$key_id,
174
$object_id,
175
$dimension_id,
176
$fact->getValue(),
177
$fact->getEpoch());
178
}
179
}
180
181
$rebuilt_ids = array_select_keys($object_map, $phids);
182
183
$table->openTransaction();
184
185
queryfx(
186
$conn,
187
'DELETE FROM %T WHERE objectID IN (%Ld)',
188
$table_name,
189
$rebuilt_ids);
190
191
if ($sql) {
192
foreach (PhabricatorLiskDAO::chunkSQL($sql) as $chunk) {
193
queryfx(
194
$conn,
195
'INSERT INTO %T
196
(keyID, objectID, dimensionID, value, epoch)
197
VALUES %LQ',
198
$table_name,
199
$chunk);
200
}
201
}
202
203
$table->saveTransaction();
204
}
205
206
}
207
208