Page MenuHomePhabricator

D12838.id.diff
No OneTemporary

D12838.id.diff

diff --git a/resources/sql/autopatches/20150514.user.cache.2.sql b/resources/sql/autopatches/20150514.user.cache.2.sql
new file mode 100644
--- /dev/null
+++ b/resources/sql/autopatches/20150514.user.cache.2.sql
@@ -0,0 +1,5 @@
+ALTER TABLE {$NAMESPACE}_user.user
+ ADD availabilityCache VARCHAR(255) COLLATE {$COLLATE_TEXT};
+
+ALTER TABLE {$NAMESPACE}_user.user
+ ADD availabilityCacheTTL INT UNSIGNED;
diff --git a/src/applications/calendar/editor/PhabricatorCalendarEventEditor.php b/src/applications/calendar/editor/PhabricatorCalendarEventEditor.php
--- a/src/applications/calendar/editor/PhabricatorCalendarEventEditor.php
+++ b/src/applications/calendar/editor/PhabricatorCalendarEventEditor.php
@@ -55,16 +55,7 @@
case PhabricatorCalendarEventTransaction::TYPE_INVITE:
$map = $xaction->getNewValue();
$phids = array_keys($map);
- $invitees = array();
-
- if ($map && !$this->getIsNewObject()) {
- $invitees = id(new PhabricatorCalendarEventInviteeQuery())
- ->setViewer($this->getActor())
- ->withEventPHIDs(array($object->getPHID()))
- ->withInviteePHIDs($phids)
- ->execute();
- $invitees = mpull($invitees, null, 'getInviteePHID');
- }
+ $invitees = mpull($object->getInvitees(), null, 'getInviteePHID');
$old = array();
foreach ($phids as $phid) {
@@ -193,6 +184,53 @@
return $xactions;
}
+ protected function applyFinalEffects($object, array $xactions) {
+
+ // Clear the availability caches for users whose availability is affected
+ // by this edit.
+
+ $invalidate_all = false;
+ $invalidate_phids = array();
+ foreach ($xactions as $xaction) {
+ switch ($xaction->getTransactionType()) {
+ case PhabricatorCalendarEventTransaction::TYPE_START_DATE:
+ case PhabricatorCalendarEventTransaction::TYPE_END_DATE:
+ case PhabricatorCalendarEventTransaction::TYPE_CANCEL:
+ case PhabricatorCalendarEventTransaction::TYPE_ALL_DAY:
+ // For these kinds of changes, we need to invalidate the availabilty
+ // caches for all attendees.
+ $invalidate_all = true;
+ break;
+ case PhabricatorCalendarEventTransaction::TYPE_INVITE:
+ foreach ($xaction->getNewValue() as $phid => $ignored) {
+ $invalidate_phids[$phid] = $phid;
+ }
+ break;
+ }
+ }
+
+ $phids = mpull($object->getInvitees(), 'getInviteePHID');
+ $phids = array_fuse($phids);
+
+ if (!$invalidate_all) {
+ $phids = array_select_keys($phids, $invalidate_phids);
+ }
+
+ if ($phids) {
+ $user = new PhabricatorUser();
+ $conn_w = $user->establishConnection('w');
+ queryfx(
+ $conn_w,
+ 'UPDATE %T SET availabilityCacheTTL = NULL
+ WHERE phid IN (%Ls) AND availabilityCacheTTL >= %d',
+ $user->getTableName(),
+ $phids,
+ $object->getDateFromForCache());
+ }
+
+ return $xactions;
+ }
+
protected function validateAllTransactions(
PhabricatorLiskDAO $object,
diff --git a/src/applications/calendar/storage/PhabricatorCalendarEvent.php b/src/applications/calendar/storage/PhabricatorCalendarEvent.php
--- a/src/applications/calendar/storage/PhabricatorCalendarEvent.php
+++ b/src/applications/calendar/storage/PhabricatorCalendarEvent.php
@@ -147,6 +147,19 @@
return parent::save();
}
+ /**
+ * Get the event start epoch for evaluating invitee availability.
+ *
+ * When assessing availability, we pretend events start earlier than they
+ * really. This allows us to mark users away for the entire duration of a
+ * series of back-to-back meetings, even if they don't strictly overlap.
+ *
+ * @return int Event start date for availability caches.
+ */
+ public function getDateFromForCache() {
+ return ($this->getDateFrom() - phutil_units('15 minutes in seconds'));
+ }
+
private static $statusTexts = array(
self::STATUS_AWAY => 'away',
self::STATUS_SPORADIC => 'sporadic',
diff --git a/src/applications/people/query/PhabricatorPeopleQuery.php b/src/applications/people/query/PhabricatorPeopleQuery.php
--- a/src/applications/people/query/PhabricatorPeopleQuery.php
+++ b/src/applications/people/query/PhabricatorPeopleQuery.php
@@ -201,8 +201,16 @@
}
if ($this->needAvailability) {
- // TODO: Add caching.
- $rebuild = $users;
+ $rebuild = array();
+ foreach ($users as $user) {
+ $cache = $user->getAvailabilityCache();
+ if ($cache !== null) {
+ $user->attachAvailability($cache);
+ } else {
+ $rebuild[] = $user;
+ }
+ }
+
if ($rebuild) {
$this->rebuildAvailabilityCache($rebuild);
}
@@ -405,11 +413,6 @@
}
}
- // Margin between meetings: pretend meetings start earlier than they do
- // so we mark you away for the entire time if you have a series of
- // back-to-back meetings, even if they don't strictly overlap.
- $margin = phutil_units('15 minutes in seconds');
-
foreach ($rebuild as $phid => $user) {
$events = idx($map, $phid, array());
@@ -419,7 +422,7 @@
// because of an event, we check again for events after that one ends.
while (true) {
foreach ($events as $event) {
- $from = ($event->getDateFrom() - $margin);
+ $from = $event->getDateFromForCache();
$to = $event->getDateTo();
if (($from <= $cursor) && ($to > $cursor)) {
$cursor = $to;
@@ -436,15 +439,16 @@
);
$availability_ttl = $cursor;
} else {
- $availability = null;
+ $availability = array(
+ 'until' => null,
+ );
$availability_ttl = $max_range;
}
// Never TTL the cache to longer than the maximum range we examined.
$availability_ttl = min($availability_ttl, $max_range);
- // TODO: Write the cache.
-
+ $user->writeAvailabilityCache($availability, $availability_ttl);
$user->attachAvailability($availability);
}
}
diff --git a/src/applications/people/storage/PhabricatorUser.php b/src/applications/people/storage/PhabricatorUser.php
--- a/src/applications/people/storage/PhabricatorUser.php
+++ b/src/applications/people/storage/PhabricatorUser.php
@@ -27,6 +27,8 @@
protected $passwordHash;
protected $profileImagePHID;
protected $profileImageCache;
+ protected $availabilityCache;
+ protected $availabilityCacheTTL;
protected $timezoneIdentifier = '';
protected $consoleEnabled = 0;
@@ -146,6 +148,8 @@
'accountSecret' => 'bytes64',
'isEnrolledInMultiFactor' => 'bool',
'profileImageCache' => 'text255?',
+ 'availabilityCache' => 'text255?',
+ 'availabilityCacheTTL' => 'uint32?',
),
self::CONFIG_KEY_SCHEMA => array(
'key_phid' => null,
@@ -166,6 +170,8 @@
),
self::CONFIG_NO_MUTATE => array(
'profileImageCache' => true,
+ 'availabilityCache' => true,
+ 'availabilityCacheTTL' => true,
),
) + parent::getConfiguration();
}
@@ -721,7 +727,7 @@
/**
* @task availability
*/
- public function attachAvailability($availability) {
+ public function attachAvailability(array $availability) {
$this->availability = $availability;
return $this;
}
@@ -762,6 +768,50 @@
}
+ /**
+ * Get cached availability, if present.
+ *
+ * @return wild|null Cache data, or null if no cache is available.
+ * @task availability
+ */
+ public function getAvailabilityCache() {
+ $now = PhabricatorTime::getNow();
+ if ($this->availabilityCacheTTL <= $now) {
+ return null;
+ }
+
+ try {
+ return phutil_json_decode($this->availabilityCache);
+ } catch (Exception $ex) {
+ return null;
+ }
+ }
+
+
+ /**
+ * Write to the availability cache.
+ *
+ * @param wild Availability cache data.
+ * @param int|null Cache TTL.
+ * @return this
+ * @task availability
+ */
+ public function writeAvailabilityCache(array $availability, $ttl) {
+ $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
+ queryfx(
+ $this->establishConnection('w'),
+ 'UPDATE %T SET availabilityCache = %s, availabilityCacheTTL = %nd
+ WHERE id = %d',
+ $this->getTableName(),
+ json_encode($availability),
+ $ttl,
+ $this->getID());
+ unset($unguarded);
+
+ return $this;
+ }
+
+
/* -( Profile Image Cache )------------------------------------------------ */

File Metadata

Mime Type
text/plain
Expires
Oct 16 2024, 12:57 AM (4 w, 5 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6711849
Default Alt Text
D12838.id.diff (8 KB)

Event Timeline