X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=application%2Fbookmark%2FBookmarkIO.php;h=8439d470da21fdff3d0b7da95230de0594e5a341;hb=8a6b7e96b7176e03238bbb1bcaa4c8b0c25e6358;hp=ae9ffcb4612bd1acbc633d51b3c48c46cd05ff76;hpb=336a28fa4a09b968ce4705900bf57693e672f0bf;p=github%2Fshaarli%2FShaarli.git diff --git a/application/bookmark/BookmarkIO.php b/application/bookmark/BookmarkIO.php index ae9ffcb4..8439d470 100644 --- a/application/bookmark/BookmarkIO.php +++ b/application/bookmark/BookmarkIO.php @@ -1,7 +1,13 @@ conf = $conf; $this->datastore = $conf->get('resource.datastore'); + $this->mutex = $mutex; } /** * Reads database from disk to memory * - * @return BookmarkArray instance + * @return Bookmark[] * - * @throws NotWritableDataStoreException Data couldn't be loaded - * @throws EmptyDataStoreException Datastore doesn't exist + * @throws NotWritableDataStoreException Data couldn't be loaded + * @throws EmptyDataStoreException Datastore file exists but does not contain any bookmark + * @throws DatastoreNotInitializedException File does not exists */ public function read() { if (! file_exists($this->datastore)) { - throw new EmptyDataStoreException(); + throw new DatastoreNotInitializedException(); } if (!is_writable($this->datastore)) { throw new NotWritableDataStoreException($this->datastore); } + $content = null; + $this->synchronized(function () use (&$content) { + $content = file_get_contents($this->datastore); + }); + // Note that gzinflate is faster than gzuncompress. // See: http://www.php.net/manual/en/function.gzdeflate.php#96439 $links = unserialize(gzinflate(base64_decode( - substr(file_get_contents($this->datastore), - strlen(self::$phpPrefix), -strlen(self::$phpSuffix))))); + substr($content, strlen(self::$phpPrefix), -strlen(self::$phpSuffix)) + ))); if (empty($links)) { if (filesize($this->datastore) > 100) { @@ -84,7 +104,7 @@ class BookmarkIO /** * Saves the database from memory to disk * - * @param BookmarkArray $links instance. + * @param Bookmark[] $links * * @throws NotWritableDataStoreException the datastore is not writable */ @@ -93,16 +113,35 @@ class BookmarkIO if (is_file($this->datastore) && !is_writeable($this->datastore)) { // The datastore exists but is not writeable throw new NotWritableDataStoreException($this->datastore); - } else if (!is_file($this->datastore) && !is_writeable(dirname($this->datastore))) { + } elseif (!is_file($this->datastore) && !is_writeable(dirname($this->datastore))) { // The datastore does not exist and its parent directory is not writeable throw new NotWritableDataStoreException(dirname($this->datastore)); } - file_put_contents( - $this->datastore, - self::$phpPrefix.base64_encode(gzdeflate(serialize($links))).self::$phpSuffix - ); + $data = self::$phpPrefix . base64_encode(gzdeflate(serialize($links))) . self::$phpSuffix; - invalidateCaches($this->conf->get('resource.page_cache')); + $this->synchronized(function () use ($data) { + file_put_contents( + $this->datastore, + $data + ); + }); + } + + /** + * Wrapper applying mutex to provided function. + * If the lock can't be acquired (e.g. some shared hosting provider), we execute the function without mutex. + * + * @see https://github.com/shaarli/Shaarli/issues/1650 + * + * @param callable $function + */ + protected function synchronized(callable $function): void + { + try { + $this->mutex->synchronized($function); + } catch (LockAcquireException $exception) { + $function(); + } } }