Page MenuHomestyx hydra

No OneTemporary

diff --git a/resources/sql/patches/029.cursors.sql b/resources/sql/patches/029.cursors.sql
new file mode 100644
index 0000000000..0512e45e12
--- /dev/null
+++ b/resources/sql/patches/029.cursors.sql
@@ -0,0 +1,13 @@
+ALTER TABLE phabricator_timeline.timeline_event
+ ADD dataID int unsigned;
+
+ALTER TABLE phabricator_timeline.timeline_event
+ ADD UNIQUE KEY (dataID);
+
+UPDATE phabricator_timeline.timeline_event e,
+ phabricator_timeline.timeline_eventdata d
+ SET e.dataID = d.id
+ WHERE d.eventID = e.id;
+
+ALTER TABLE phabricator_timeline.timeline_eventdata
+ DROP eventID;
diff --git a/scripts/sql/upgrade_schema.php b/scripts/sql/upgrade_schema.php
index 3cc2854009..26417647c2 100755
--- a/scripts/sql/upgrade_schema.php
+++ b/scripts/sql/upgrade_schema.php
@@ -1,142 +1,153 @@
#!/usr/bin/env php
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
$root = dirname(dirname(dirname(__FILE__)));
require_once $root.'/scripts/__init_script__.php';
require_once $root.'/scripts/__init_env__.php';
+phutil_require_module('phutil', 'console');
+
const TABLE_NAME = 'schema_version';
if (isset($argv[1]) && !is_numeric($argv[1])) {
print
"USAGE: ./update_schema.php [first_patch_version]\n\n".
"run './update_schema.php 12' to apply all patches starting from ".
"version 12.\n".
"run './update_schema.php' to apply all patches that are new since\n".
"the last time this script was run\n\n";
exit(0);
}
+echo phutil_console_wrap(
+ "Before running this script, you should take down the Phabricator web ".
+ "interface and stop any running Phabricator daemons.");
+
+if (!phutil_console_confirm('Are you ready to continue?')) {
+ echo "Cancelled.\n";
+ exit(1);
+}
+
// Use always the version from the commandline if it is defined
$next_version = isset($argv[1]) ? (int)$argv[1] : null;
// Dummy class needed for creating our database
class DummyUser extends PhabricatorLiskDAO {
public function getApplicationName() {
return 'user';
}
}
// Class needed for setting up the actual SQL connection
class PhabricatorSchemaVersion extends PhabricatorLiskDAO {
public function getApplicationName() {
return 'meta_data';
}
}
// Connect to 'phabricator_user' db first to create our db
$conn = id(new DummyUser())->establishConnection('w');
$create_sql = <<<END
CREATE DATABASE IF NOT EXISTS `phabricator_meta_data`;
END;
queryfx($conn, $create_sql);
// 'phabricator_meta_data' database exists, let's connect to it now
$conn = id(new PhabricatorSchemaVersion())->establishConnection('w');
$create_sql = <<<END
CREATE TABLE IF NOT EXISTS phabricator_meta_data.`schema_version` (
`version` INTEGER not null
);
END;
queryfx($conn, $create_sql);
// Get the version only if commandline argument wasn't given
if ($next_version === null) {
$version = queryfx_one(
$conn,
'SELECT * FROM %T',
TABLE_NAME);
if (!$version) {
print "*** No version information in the database ***\n";
print "*** Give the first patch version which to ***\n";
print "*** apply as the command line argument ***\n";
exit(-1);
}
$next_version = $version['version'] + 1;
}
// Find the patch files
$patches_dir = $root.'/resources/sql/patches/';
$finder = id(new FileFinder($patches_dir))
->withSuffix('sql');
$results = $finder->find();
$patches = array();
foreach ($results as $r) {
$matches = array();
if (preg_match('/(\d+)\..*\.sql$/', $r, $matches)) {
$patches[] = array('version' => (int)$matches[1],
'file' => $r);
} else {
print
"*** WARNING : File {$r} does not follow the normal naming ".
"convention. ***\n";
}
}
// Files are in some 'random' order returned by the operating system
// We need to apply them in proper order
$patches = isort($patches, 'version');
$patch_applied = false;
foreach ($patches as $patch) {
if ($patch['version'] < $next_version) {
continue;
}
print "Applying patch {$patch['file']}\n";
$path = Filesystem::resolvePath($patches_dir.$patch['file']);
$user = PhabricatorEnv::getEnvConfig('mysql.user');
$pass = PhabricatorEnv::getEnvConfig('mysql.pass');
$host = PhabricatorEnv::getEnvConfig('mysql.host');
list($stdout, $stderr) = execx(
"mysql --user=%s --password=%s --host=%s < %s",
$user, $pass, $host, $path);
if ($stderr) {
print $stderr;
exit(-1);
}
// Patch was successful, update the db with the latest applied patch version
// 'DELETE' and 'INSERT' instead of update, because the table might be empty
queryfx($conn, 'DELETE FROM %T', TABLE_NAME);
queryfx($conn, 'INSERT INTO %T values (%d)', TABLE_NAME, $patch['version']);
$patch_applied = true;
}
if (!$patch_applied) {
print "Your database is already up-to-date\n";
}
diff --git a/src/applications/daemon/controller/timelineevent/PhabricatorDaemonTimelineEventController.php b/src/applications/daemon/controller/timelineevent/PhabricatorDaemonTimelineEventController.php
index 126d37a1b4..a1499d141d 100644
--- a/src/applications/daemon/controller/timelineevent/PhabricatorDaemonTimelineEventController.php
+++ b/src/applications/daemon/controller/timelineevent/PhabricatorDaemonTimelineEventController.php
@@ -1,79 +1,80 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class PhabricatorDaemonTimelineEventController
extends PhabricatorDaemonController {
private $id;
public function willProcessRequest(array $data) {
$this->id = $data['id'];
}
public function processRequest() {
$event = id(new PhabricatorTimelineEvent('NULL'))->load($this->id);
if (!$event) {
return new Aphront404Response();
}
$request = $this->getRequest();
$user = $request->getUser();
- $data = id(new PhabricatorTimelineEventData())->loadOneWhere(
- 'eventID = %d',
- $event->getID());
+ if ($event->getDataID()) {
+ $data = id(new PhabricatorTimelineEventData())->load(
+ $event->getDataID());
+ }
if ($data) {
$data = json_encode($data->getEventData());
} else {
$data = 'null';
}
$form = new AphrontFormView();
$form
->setUser($user)
->appendChild(
id(new AphrontFormStaticControl())
->setLabel('ID')
->setValue($event->getID()))
->appendChild(
id(new AphrontFormStaticControl())
->setLabel('Type')
->setValue($event->getType()))
->appendChild(
id(new AphrontFormTextAreaControl())
->setDisabled(true)
->setLabel('Data')
->setValue($data))
->appendChild(
id(new AphrontFormSubmitControl())
->addCancelButton('/daemon/timeline/'));
$panel = new AphrontPanelView();
$panel->setHeader('Event');
$panel->setWidth(AphrontPanelView::WIDTH_FORM);
$panel->appendChild($form);
return $this->buildStandardPageResponse(
$panel,
array(
'title' => 'Timeline Event',
));
}
}
diff --git a/src/infrastructure/daemon/timeline/cursor/iterator/PhabricatorTimelineIterator.php b/src/infrastructure/daemon/timeline/cursor/iterator/PhabricatorTimelineIterator.php
index 1aadedeefc..0fc1b5bcd4 100644
--- a/src/infrastructure/daemon/timeline/cursor/iterator/PhabricatorTimelineIterator.php
+++ b/src/infrastructure/daemon/timeline/cursor/iterator/PhabricatorTimelineIterator.php
@@ -1,116 +1,116 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class PhabricatorTimelineIterator implements Iterator {
protected $cursorName;
protected $eventTypes;
protected $cursor;
protected $index = -1;
protected $events = array();
const LOAD_CHUNK_SIZE = 128;
public function __construct($cursor_name, array $event_types) {
$this->cursorName = $cursor_name;
$this->eventTypes = $event_types;
}
protected function loadEvents() {
if (!$this->cursor) {
$this->cursor = id(new PhabricatorTimelineCursor())->loadOneWhere(
'name = %s',
$this->cursorName);
if (!$this->cursor) {
$cursor = new PhabricatorTimelineCursor();
$cursor->setName($this->cursorName);
$cursor->setPosition(0);
$cursor->save();
$this->cursor = $cursor;
}
}
$event = new PhabricatorTimelineEvent('NULL');
$event_data = new PhabricatorTimelineEventData();
$raw_data = queryfx_all(
$event->establishConnection('r'),
'SELECT event.*, event_data.eventData eventData
FROM %T event
- LEFT JOIN %T event_data ON event_data.eventID = event.id
+ LEFT JOIN %T event_data ON event_data.id = event.dataID
WHERE event.id > %d AND event.type in (%Ls)
ORDER BY event.id ASC LIMIT %d',
$event->getTableName(),
$event_data->getTableName(),
$this->cursor->getPosition(),
$this->eventTypes,
self::LOAD_CHUNK_SIZE);
$events = $event->loadAllFromArray($raw_data);
$events = mpull($events, null, 'getID');
$raw_data = ipull($raw_data, 'eventData', 'id');
foreach ($raw_data as $id => $data) {
if ($data) {
$decoded = json_decode($data, true);
$events[$id]->setData($decoded);
}
}
$this->events = $events;
if ($this->events) {
$this->events = array_values($this->events);
$this->index = 0;
} else {
$this->cursor = null;
}
}
public function current() {
return $this->events[$this->index];
}
public function key() {
return $this->events[$this->index]->getID();
}
public function next() {
if ($this->valid()) {
$this->cursor->setPosition($this->key());
$this->cursor->save();
}
$this->index++;
if (!$this->valid()) {
$this->loadEvents();
}
}
public function valid() {
return isset($this->events[$this->index]);
}
public function rewind() {
if (!$this->valid()) {
$this->loadEvents();
}
}
}
diff --git a/src/infrastructure/daemon/timeline/storage/event/PhabricatorTimelineEvent.php b/src/infrastructure/daemon/timeline/storage/event/PhabricatorTimelineEvent.php
index 966fa4e94d..8ff507624a 100644
--- a/src/infrastructure/daemon/timeline/storage/event/PhabricatorTimelineEvent.php
+++ b/src/infrastructure/daemon/timeline/storage/event/PhabricatorTimelineEvent.php
@@ -1,65 +1,71 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class PhabricatorTimelineEvent extends PhabricatorTimelineDAO {
protected $type;
+ protected $dataID;
+
private $data;
public function __construct($type, $data = null) {
parent::__construct();
if (strlen($type) !== 4) {
throw new Exception("Event types must be exactly 4 characters long.");
}
$this->type = $type;
$this->data = $data;
}
public function getConfiguration() {
return array(
self::CONFIG_TIMESTAMPS => false,
) + parent::getConfiguration();
}
public function recordEvent() {
if ($this->getID()) {
throw new Exception("Event has already been recorded!");
}
- $this->save();
-
+ // Save the data first and point to it from the event to avoid a race
+ // condition where we insert the event before the data and a consumer reads
+ // it immediately.
if ($this->data !== null) {
$data = new PhabricatorTimelineEventData();
- $data->setEventID($this->getID());
$data->setEventData($this->data);
$data->save();
+
+ $this->setDataID($data->getID());
}
+
+ $this->save();
}
public function setData($data) {
$this->data = $data;
return $this;
}
public function getData() {
return $this->data;
}
}
diff --git a/src/infrastructure/daemon/timeline/storage/eventdata/PhabricatorTimelineEventData.php b/src/infrastructure/daemon/timeline/storage/eventdata/PhabricatorTimelineEventData.php
index 0bcf9d3035..407d4e1ece 100644
--- a/src/infrastructure/daemon/timeline/storage/eventdata/PhabricatorTimelineEventData.php
+++ b/src/infrastructure/daemon/timeline/storage/eventdata/PhabricatorTimelineEventData.php
@@ -1,33 +1,32 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class PhabricatorTimelineEventData extends PhabricatorTimelineDAO {
- protected $eventID;
protected $eventData;
public function getConfiguration() {
return array(
self::CONFIG_SERIALIZATION => array(
'eventData' => self::SERIALIZATION_JSON,
),
self::CONFIG_TIMESTAMPS => false,
) + parent::getConfiguration();
}
}

File Metadata

Mime Type
text/x-diff
Expires
Mon, Dec 1, 8:33 AM (1 d, 12 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
430312
Default Alt Text
(15 KB)

Event Timeline