]> git.immae.eu Git - github/shaarli/Shaarli.git/commitdiff
Add mutex on datastore I/O operations 1570/head
authorArthurHoaro <arthur@hoa.ro>
Sat, 26 Sep 2020 12:18:01 +0000 (14:18 +0200)
committerArthurHoaro <arthur@hoa.ro>
Tue, 13 Oct 2020 10:38:19 +0000 (12:38 +0200)
To make sure that there is no concurrent operation on the datastore file.

Fixes #1132

26 files changed:
application/api/ApiMiddleware.php
application/bookmark/BookmarkFileService.php
application/bookmark/BookmarkIO.php
application/bookmark/BookmarkServiceInterface.php
application/container/ContainerBuilder.php
composer.json
composer.lock
init.php
tests/api/controllers/info/InfoTest.php
tests/api/controllers/links/DeleteLinkTest.php
tests/api/controllers/links/GetLinkIdTest.php
tests/api/controllers/links/GetLinksTest.php
tests/api/controllers/links/PostLinkTest.php
tests/api/controllers/links/PutLinkTest.php
tests/api/controllers/tags/DeleteTagTest.php
tests/api/controllers/tags/GetTagNameTest.php
tests/api/controllers/tags/GetTagsTest.php
tests/api/controllers/tags/PutTagTest.php
tests/bookmark/BookmarkFileServiceTest.php
tests/bookmark/BookmarkFilterTest.php
tests/bookmark/BookmarkInitializerTest.php
tests/bootstrap.php
tests/feed/FeedBuilderTest.php
tests/netscape/BookmarkExportTest.php
tests/netscape/BookmarkImportTest.php
tests/updater/UpdaterTest.php

index f5b53b01fcc5f5f16c5d477d054c9483d2e142d9..adc8b2666306d185f70fb0668fcefdf2b40b7d13 100644 (file)
@@ -1,6 +1,7 @@
 <?php
 namespace Shaarli\Api;
 
+use malkusch\lock\mutex\FlockMutex;
 use Shaarli\Api\Exceptions\ApiAuthorizationException;
 use Shaarli\Api\Exceptions\ApiException;
 use Shaarli\Bookmark\BookmarkFileService;
@@ -143,6 +144,7 @@ class ApiMiddleware
         $linkDb = new BookmarkFileService(
             $conf,
             $this->container->get('history'),
+            new FlockMutex(fopen(SHAARLI_MUTEX_FILE, 'r'), 2),
             true
         );
         $this->container['db'] = $linkDb;
index c9ec260930d159f8603f1f5c796fbec5612c08c2..1ba0071277a26684808ae337716231d68fd138b9 100644 (file)
@@ -5,6 +5,7 @@ namespace Shaarli\Bookmark;
 
 
 use Exception;
+use malkusch\lock\mutex\Mutex;
 use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
 use Shaarli\Bookmark\Exception\DatastoreNotInitializedException;
 use Shaarli\Bookmark\Exception\EmptyDataStoreException;
@@ -47,15 +48,19 @@ class BookmarkFileService implements BookmarkServiceInterface
     /** @var bool true for logged in users. Default value to retrieve private bookmarks. */
     protected $isLoggedIn;
 
+    /** @var Mutex */
+    protected $mutex;
+
     /**
      * @inheritDoc
      */
-    public function __construct(ConfigManager $conf, History $history, $isLoggedIn)
+    public function __construct(ConfigManager $conf, History $history, Mutex $mutex, $isLoggedIn)
     {
         $this->conf = $conf;
         $this->history = $history;
+        $this->mutex = $mutex;
         $this->pageCacheManager = new PageCacheManager($this->conf->get('resource.page_cache'), $isLoggedIn);
-        $this->bookmarksIO = new BookmarkIO($this->conf);
+        $this->bookmarksIO = new BookmarkIO($this->conf, $this->mutex);
         $this->isLoggedIn = $isLoggedIn;
 
         if (!$this->isLoggedIn && $this->conf->get('privacy.hide_public_links', false)) {
index 6bf7f3654ebfdd41f87b9468f00c135c2725e9da..099653b0e62d0b7acc7adee5c6f573c721238611 100644 (file)
@@ -2,6 +2,8 @@
 
 namespace Shaarli\Bookmark;
 
+use malkusch\lock\mutex\Mutex;
+use malkusch\lock\mutex\NoMutex;
 use Shaarli\Bookmark\Exception\DatastoreNotInitializedException;
 use Shaarli\Bookmark\Exception\EmptyDataStoreException;
 use Shaarli\Bookmark\Exception\NotWritableDataStoreException;
@@ -27,11 +29,14 @@ class BookmarkIO
      */
     protected $conf;
 
+
+    /** @var Mutex */
+    protected $mutex;
+
     /**
      * string Datastore PHP prefix
      */
     protected static $phpPrefix = '<?php /* ';
-
     /**
      * string Datastore PHP suffix
      */
@@ -42,10 +47,15 @@ class BookmarkIO
      *
      * @param ConfigManager $conf instance
      */
-    public function __construct($conf)
+    public function __construct(ConfigManager $conf, Mutex $mutex = null)
     {
+        if ($mutex === null) {
+            // This should only happen with legacy classes
+            $mutex = new NoMutex();
+        }
         $this->conf = $conf;
         $this->datastore = $conf->get('resource.datastore');
+        $this->mutex = $mutex;
     }
 
     /**
@@ -67,11 +77,16 @@ class BookmarkIO
             throw new NotWritableDataStoreException($this->datastore);
         }
 
+        $content = null;
+        $this->mutex->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) {
@@ -100,9 +115,13 @@ class BookmarkIO
             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;
+
+        $this->mutex->synchronized(function () use ($data) {
+            file_put_contents(
+                $this->datastore,
+                $data
+            );
+        });
     }
 }
index b9b483eb8ae14ae70582ec5589eb67fd9f066558..638cfa5fd73be1bc972b1391308ca88fd459b411 100644 (file)
@@ -5,8 +5,6 @@ namespace Shaarli\Bookmark;
 
 use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
 use Shaarli\Bookmark\Exception\NotWritableDataStoreException;
-use Shaarli\Config\ConfigManager;
-use Shaarli\History;
 
 /**
  * Class BookmarksService
@@ -15,15 +13,6 @@ use Shaarli\History;
  */
 interface BookmarkServiceInterface
 {
-    /**
-     * BookmarksService constructor.
-     *
-     * @param ConfigManager $conf       instance
-     * @param History       $history    instance
-     * @param bool          $isLoggedIn true if the current user is logged in
-     */
-    public function __construct(ConfigManager $conf, History $history, $isLoggedIn);
-
     /**
      * Find a bookmark by hash
      *
index 55bb51b5b46506f95b2d79280796c694cc1e9fc9..c21d58ddde92f8eb0794d1fc99f24217d11f94b7 100644 (file)
@@ -4,6 +4,7 @@ declare(strict_types=1);
 
 namespace Shaarli\Container;
 
+use malkusch\lock\mutex\FlockMutex;
 use Shaarli\Bookmark\BookmarkFileService;
 use Shaarli\Bookmark\BookmarkServiceInterface;
 use Shaarli\Config\ConfigManager;
@@ -84,6 +85,7 @@ class ContainerBuilder
             return new BookmarkFileService(
                 $container->conf,
                 $container->history,
+                new FlockMutex(fopen(SHAARLI_MUTEX_FILE, 'r'), 2),
                 $container->loginManager->isLoggedIn()
             );
         };
index 7e675623c051abf9e917becbbf57e9107cb580f9..c0855e4743a443abf4487f7a7eee60b803e84fe5 100644 (file)
@@ -23,6 +23,7 @@
         "erusev/parsedown": "^1.6",
         "erusev/parsedown-extra": "^0.8.1",
         "gettext/gettext": "^4.4",
+        "malkusch/lock": "^2.1",
         "pubsubhubbub/publisher": "dev-master",
         "shaarli/netscape-bookmark-parser": "^2.1",
         "slim/slim": "^3.0"
index e02491ff3f7c70db800e7433d16461faac5866e4..c379d8e770bcde9c325b373b6f8315e5ea79a8f8 100644 (file)
@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "f84918821b0dceb0cd569875c0418bb8",
+    "content-hash": "932b191006135ff8be495aa0b4ba7e09",
     "packages": [
         {
             "name": "arthurhoaro/web-thumbnailer",
             },
             "time": "2016-11-07T19:29:14+00:00"
         },
+        {
+            "name": "malkusch/lock",
+            "version": "v2.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-lock/lock.git",
+                "reference": "093f389ec2f38fc8686d2f70e23378182fce7714"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-lock/lock/zipball/093f389ec2f38fc8686d2f70e23378182fce7714",
+                "reference": "093f389ec2f38fc8686d2f70e23378182fce7714",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.1",
+                "psr/log": "^1"
+            },
+            "require-dev": {
+                "eloquent/liberator": "^2.0",
+                "ext-memcached": "*",
+                "ext-pcntl": "*",
+                "ext-pdo_mysql": "*",
+                "ext-pdo_sqlite": "*",
+                "ext-redis": "*",
+                "ext-sysvsem": "*",
+                "johnkary/phpunit-speedtrap": "^3.0",
+                "kriswallsmith/spork": "^0.3",
+                "mikey179/vfsstream": "^1.6",
+                "php-mock/php-mock-phpunit": "^2.1",
+                "phpunit/phpunit": "^7.4",
+                "predis/predis": "^1.1",
+                "squizlabs/php_codesniffer": "^3.3"
+            },
+            "suggest": {
+                "ext-pnctl": "Enables locking with flock without busy waiting in CLI scripts.",
+                "ext-redis": "To use this library with the PHP Redis extension.",
+                "ext-sysvsem": "Enables locking using semaphores.",
+                "predis/predis": "To use this library with predis."
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "malkusch\\lock\\": "classes/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "WTFPL"
+            ],
+            "authors": [
+                {
+                    "name": "Markus Malkusch",
+                    "email": "markus@malkusch.de",
+                    "homepage": "http://markus.malkusch.de",
+                    "role": "Developer"
+                },
+                {
+                    "name": "Willem Stuursma-Ruwen",
+                    "email": "willem@stuursma.name",
+                    "role": "Developer"
+                }
+            ],
+            "description": "Mutex library for exclusive code execution.",
+            "homepage": "https://github.com/malkusch/lock",
+            "keywords": [
+                "advisory-locks",
+                "cas",
+                "flock",
+                "lock",
+                "locking",
+                "memcache",
+                "mutex",
+                "mysql",
+                "postgresql",
+                "redis",
+                "redlock",
+                "semaphore"
+            ],
+            "support": {
+                "issues": "https://github.com/php-lock/lock/issues",
+                "source": "https://github.com/php-lock/lock/tree/v2.1"
+            },
+            "time": "2018-12-12T19:53:29+00:00"
+        },
         {
             "name": "nikic/fast-route",
             "version": "v1.3.0",
index f0b8436806bde75bc374b58f5dcb91c81784946c..ab0e4ea743648684298d048a1e2e01ea7f9c9d02 100644 (file)
--- a/init.php
+++ b/init.php
@@ -60,6 +60,7 @@ ini_set('session.use_only_cookies', 1);
 ini_set('session.use_trans_sid', false);
 
 define('SHAARLI_VERSION', ApplicationUtils::getVersion(__DIR__ .'/'. ApplicationUtils::$VERSION_FILE));
+define('SHAARLI_MUTEX_FILE', __FILE__);
 
 session_name('shaarli');
 // Start session if needed (Some server auto-start sessions).
index 1598e1e8ac8e8edec612eb79cbe969ed22f1676f..10b29ab2530bdf9c9752aef9c149ba7c6feeebed 100644 (file)
@@ -1,6 +1,7 @@
 <?php
 namespace Shaarli\Api\Controllers;
 
+use malkusch\lock\mutex\NoMutex;
 use Shaarli\Bookmark\BookmarkFileService;
 use Shaarli\Config\ConfigManager;
 use Shaarli\History;
@@ -49,6 +50,7 @@ class InfoTest extends TestCase
      */
     protected function setUp(): void
     {
+        $mutex = new NoMutex();
         $this->conf = new ConfigManager('tests/utils/config/configJson');
         $this->conf->set('resource.datastore', self::$testDatastore);
         $this->refDB = new \ReferenceLinkDB();
@@ -58,7 +60,7 @@ class InfoTest extends TestCase
 
         $this->container = new Container();
         $this->container['conf'] = $this->conf;
-        $this->container['db'] = new BookmarkFileService($this->conf, $history, true);
+        $this->container['db'] = new BookmarkFileService($this->conf, $history, $mutex, true);
         $this->container['history'] = null;
 
         $this->controller = new Info($this->container);
index cf9464f07877e1613ae0b5704ed2a523da23c497..805c9be33be49c0523ef23311d930c356b252c11 100644 (file)
@@ -3,6 +3,7 @@
 
 namespace Shaarli\Api\Controllers;
 
+use malkusch\lock\mutex\NoMutex;
 use Shaarli\Bookmark\BookmarkFileService;
 use Shaarli\Config\ConfigManager;
 use Shaarli\History;
@@ -53,11 +54,15 @@ class DeleteLinkTest extends \Shaarli\TestCase
      */
     protected $controller;
 
+    /** @var NoMutex */
+    protected $mutex;
+
     /**
      * Before each test, instantiate a new Api with its config, plugins and bookmarks.
      */
     protected function setUp(): void
     {
+        $this->mutex = new NoMutex();
         $this->conf = new ConfigManager('tests/utils/config/configJson');
         $this->conf->set('resource.datastore', self::$testDatastore);
         $this->refDB = new \ReferenceLinkDB();
@@ -65,7 +70,7 @@ class DeleteLinkTest extends \Shaarli\TestCase
         $refHistory = new \ReferenceHistory();
         $refHistory->write(self::$testHistory);
         $this->history = new History(self::$testHistory);
-        $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true);
+        $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
 
         $this->container = new Container();
         $this->container['conf'] = $this->conf;
@@ -100,7 +105,7 @@ class DeleteLinkTest extends \Shaarli\TestCase
         $this->assertEquals(204, $response->getStatusCode());
         $this->assertEmpty((string) $response->getBody());
 
-        $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true);
+        $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
         $this->assertFalse($this->bookmarkService->exists($id));
 
         $historyEntry = $this->history->getHistory()[0];
index 99dc606fbf95c1d6bae7ef716a4fa335a55491e4..1ec56ef3cd97c870fc52b7bbb54875178c52a6ea 100644 (file)
@@ -2,6 +2,7 @@
 
 namespace Shaarli\Api\Controllers;
 
+use malkusch\lock\mutex\NoMutex;
 use Shaarli\Bookmark\Bookmark;
 use Shaarli\Bookmark\BookmarkFileService;
 use Shaarli\Config\ConfigManager;
@@ -57,6 +58,7 @@ class GetLinkIdTest extends \Shaarli\TestCase
      */
     protected function setUp(): void
     {
+        $mutex = new NoMutex();
         $this->conf = new ConfigManager('tests/utils/config/configJson');
         $this->conf->set('resource.datastore', self::$testDatastore);
         $this->refDB = new \ReferenceLinkDB();
@@ -65,7 +67,7 @@ class GetLinkIdTest extends \Shaarli\TestCase
 
         $this->container = new Container();
         $this->container['conf'] = $this->conf;
-        $this->container['db'] = new BookmarkFileService($this->conf, $history, true);
+        $this->container['db'] = new BookmarkFileService($this->conf, $history, $mutex, true);
         $this->container['history'] = null;
 
         $this->controller = new Links($this->container);
index ca1bfc6362d550de19805938f397938344f409f7..0f5073b47197470491982856b167529b86310bec 100644 (file)
@@ -1,6 +1,7 @@
 <?php
 namespace Shaarli\Api\Controllers;
 
+use malkusch\lock\mutex\NoMutex;
 use Shaarli\Bookmark\Bookmark;
 use Shaarli\Bookmark\BookmarkFileService;
 use Shaarli\Bookmark\LinkDB;
@@ -57,6 +58,7 @@ class GetLinksTest extends \Shaarli\TestCase
      */
     protected function setUp(): void
     {
+        $mutex = new NoMutex();
         $this->conf = new ConfigManager('tests/utils/config/configJson');
         $this->conf->set('resource.datastore', self::$testDatastore);
         $this->refDB = new \ReferenceLinkDB();
@@ -65,7 +67,7 @@ class GetLinksTest extends \Shaarli\TestCase
 
         $this->container = new Container();
         $this->container['conf'] = $this->conf;
-        $this->container['db'] = new BookmarkFileService($this->conf, $history, true);
+        $this->container['db'] = new BookmarkFileService($this->conf, $history, $mutex, true);
         $this->container['history'] = null;
 
         $this->controller = new Links($this->container);
index 20694571de7857415e71c15fd2cb09d8fc6593ef..7ff92f5c96968c6e12c75098dc164526c0a3224d 100644 (file)
@@ -2,6 +2,7 @@
 
 namespace Shaarli\Api\Controllers;
 
+use malkusch\lock\mutex\NoMutex;
 use Shaarli\Bookmark\Bookmark;
 use Shaarli\Bookmark\BookmarkFileService;
 use Shaarli\Config\ConfigManager;
@@ -72,6 +73,7 @@ class PostLinkTest extends TestCase
      */
     protected function setUp(): void
     {
+        $mutex = new NoMutex();
         $this->conf = new ConfigManager('tests/utils/config/configJson');
         $this->conf->set('resource.datastore', self::$testDatastore);
         $this->refDB = new \ReferenceLinkDB();
@@ -79,7 +81,7 @@ class PostLinkTest extends TestCase
         $refHistory = new \ReferenceHistory();
         $refHistory->write(self::$testHistory);
         $this->history = new History(self::$testHistory);
-        $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true);
+        $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $mutex, true);
 
         $this->container = new Container();
         $this->container['conf'] = $this->conf;
index a2e87c5986304938662c33d05d21d7cbb313f60e..240ee323a345cff812cc9ad529ea4ebe25f1ca7a 100644 (file)
@@ -3,6 +3,7 @@
 
 namespace Shaarli\Api\Controllers;
 
+use malkusch\lock\mutex\NoMutex;
 use Shaarli\Bookmark\Bookmark;
 use Shaarli\Bookmark\BookmarkFileService;
 use Shaarli\Config\ConfigManager;
@@ -64,6 +65,7 @@ class PutLinkTest extends \Shaarli\TestCase
      */
     protected function setUp(): void
     {
+        $mutex = new NoMutex();
         $this->conf = new ConfigManager('tests/utils/config/configJson');
         $this->conf->set('resource.datastore', self::$testDatastore);
         $this->refDB = new \ReferenceLinkDB();
@@ -71,7 +73,7 @@ class PutLinkTest extends \Shaarli\TestCase
         $refHistory = new \ReferenceHistory();
         $refHistory->write(self::$testHistory);
         $this->history = new History(self::$testHistory);
-        $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true);
+        $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $mutex, true);
 
         $this->container = new Container();
         $this->container['conf'] = $this->conf;
index 1326eb47aa7751f20885cb37df764f860097e0f7..37f0722978c2e2ee4fc2a2a45589b4fd28f1ffe0 100644 (file)
@@ -3,6 +3,7 @@
 
 namespace Shaarli\Api\Controllers;
 
+use malkusch\lock\mutex\NoMutex;
 use Shaarli\Bookmark\BookmarkFileService;
 use Shaarli\Bookmark\LinkDB;
 use Shaarli\Config\ConfigManager;
@@ -54,11 +55,15 @@ class DeleteTagTest extends \Shaarli\TestCase
      */
     protected $controller;
 
+    /** @var NoMutex */
+    protected $mutex;
+
     /**
      * Before each test, instantiate a new Api with its config, plugins and bookmarks.
      */
     protected function setUp(): void
     {
+        $this->mutex = new NoMutex();
         $this->conf = new ConfigManager('tests/utils/config/configJson');
         $this->conf->set('resource.datastore', self::$testDatastore);
         $this->refDB = new \ReferenceLinkDB();
@@ -66,7 +71,7 @@ class DeleteTagTest extends \Shaarli\TestCase
         $refHistory = new \ReferenceHistory();
         $refHistory->write(self::$testHistory);
         $this->history = new History(self::$testHistory);
-        $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true);
+        $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
 
         $this->container = new Container();
         $this->container['conf'] = $this->conf;
@@ -102,7 +107,7 @@ class DeleteTagTest extends \Shaarli\TestCase
         $this->assertEquals(204, $response->getStatusCode());
         $this->assertEmpty((string) $response->getBody());
 
-        $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true);
+        $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
         $tags = $this->bookmarkService->bookmarksCountPerTag();
         $this->assertFalse(isset($tags[$tagName]));
 
@@ -136,7 +141,7 @@ class DeleteTagTest extends \Shaarli\TestCase
         $this->assertEquals(204, $response->getStatusCode());
         $this->assertEmpty((string) $response->getBody());
 
-        $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true);
+        $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
         $tags = $this->bookmarkService->bookmarksCountPerTag();
         $this->assertFalse(isset($tags[$tagName]));
         $this->assertTrue($tags[strtolower($tagName)] > 0);
index 9c05954b4e8131f4a22664f59761cb40ee6f1324..878de5a4202d2dbb5a2e54ec2f29a719cc8a5412 100644 (file)
@@ -2,6 +2,7 @@
 
 namespace Shaarli\Api\Controllers;
 
+use malkusch\lock\mutex\NoMutex;
 use Shaarli\Bookmark\BookmarkFileService;
 use Shaarli\Bookmark\LinkDB;
 use Shaarli\Config\ConfigManager;
@@ -55,6 +56,7 @@ class GetTagNameTest extends \Shaarli\TestCase
      */
     protected function setUp(): void
     {
+        $mutex = new NoMutex();
         $this->conf = new ConfigManager('tests/utils/config/configJson');
         $this->conf->set('resource.datastore', self::$testDatastore);
         $this->refDB = new \ReferenceLinkDB();
@@ -63,7 +65,7 @@ class GetTagNameTest extends \Shaarli\TestCase
 
         $this->container = new Container();
         $this->container['conf'] = $this->conf;
-        $this->container['db'] = new BookmarkFileService($this->conf, $history, true);
+        $this->container['db'] = new BookmarkFileService($this->conf, $history, $mutex, true);
         $this->container['history'] = null;
 
         $this->controller = new Tags($this->container);
index 3459fdfae361deb737f9e40786e6102a367d223b..b565a8c4d3620eba8282d871c3c63b5094815d3b 100644 (file)
@@ -1,6 +1,7 @@
 <?php
 namespace Shaarli\Api\Controllers;
 
+use malkusch\lock\mutex\NoMutex;
 use Shaarli\Bookmark\BookmarkFileService;
 use Shaarli\Bookmark\LinkDB;
 use Shaarli\Config\ConfigManager;
@@ -59,13 +60,14 @@ class GetTagsTest extends \Shaarli\TestCase
      */
     protected function setUp(): void
     {
+        $mutex = new NoMutex();
         $this->conf = new ConfigManager('tests/utils/config/configJson');
         $this->conf->set('resource.datastore', self::$testDatastore);
         $this->refDB = new \ReferenceLinkDB();
         $this->refDB->write(self::$testDatastore);
         $history = new History('sandbox/history.php');
 
-        $this->bookmarkService = new BookmarkFileService($this->conf, $history, true);
+        $this->bookmarkService = new BookmarkFileService($this->conf, $history, $mutex, true);
 
         $this->container = new Container();
         $this->container['conf'] = $this->conf;
index 74edde787b745dbddeda6308e51d94c8bd8df61f..c73f6d3beaec758d1318599c46b9b477bdd66189 100644 (file)
@@ -2,6 +2,7 @@
 
 namespace Shaarli\Api\Controllers;
 
+use malkusch\lock\mutex\NoMutex;
 use Shaarli\Api\Exceptions\ApiBadParametersException;
 use Shaarli\Bookmark\BookmarkFileService;
 use Shaarli\Bookmark\LinkDB;
@@ -64,6 +65,7 @@ class PutTagTest extends \Shaarli\TestCase
      */
     protected function setUp(): void
     {
+        $mutex = new NoMutex();
         $this->conf = new ConfigManager('tests/utils/config/configJson');
         $this->conf->set('resource.datastore', self::$testDatastore);
         $this->refDB = new \ReferenceLinkDB();
@@ -71,7 +73,7 @@ class PutTagTest extends \Shaarli\TestCase
         $refHistory = new \ReferenceHistory();
         $refHistory->write(self::$testHistory);
         $this->history = new History(self::$testHistory);
-        $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true);
+        $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $mutex, true);
 
         $this->container = new Container();
         $this->container['conf'] = $this->conf;
index c399822b5801520b78c511d91cff5d312ba2b693..6c56dfaabbcb84655e82d75342f1b031332cd52c 100644 (file)
@@ -6,6 +6,7 @@
 namespace Shaarli\Bookmark;
 
 use DateTime;
+use malkusch\lock\mutex\NoMutex;
 use ReferenceLinkDB;
 use ReflectionClass;
 use Shaarli;
@@ -52,6 +53,9 @@ class BookmarkFileServiceTest extends TestCase
      */
     protected $privateLinkDB = null;
 
+    /** @var NoMutex */
+    protected $mutex;
+
     /**
      * Instantiates public and private LinkDBs with test data
      *
@@ -68,6 +72,8 @@ class BookmarkFileServiceTest extends TestCase
      */
     protected function setUp(): void
     {
+        $this->mutex = new NoMutex();
+
         if (file_exists(self::$testDatastore)) {
             unlink(self::$testDatastore);
         }
@@ -87,8 +93,8 @@ class BookmarkFileServiceTest extends TestCase
         $this->refDB = new \ReferenceLinkDB();
         $this->refDB->write(self::$testDatastore);
         $this->history = new History('sandbox/history.php');
-        $this->publicLinkDB = new BookmarkFileService($this->conf, $this->history, false);
-        $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true);
+        $this->publicLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, false);
+        $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
     }
 
     /**
@@ -105,7 +111,7 @@ class BookmarkFileServiceTest extends TestCase
         $db = self::getMethod('migrate');
         $db->invokeArgs($this->privateLinkDB, []);
 
-        $db = new \FakeBookmarkService($this->conf, $this->history, true);
+        $db = new \FakeBookmarkService($this->conf, $this->history, $this->mutex, true);
         $this->assertInstanceOf(BookmarkArray::class, $db->getBookmarks());
         $this->assertEquals($this->refDB->countLinks(), $db->count());
     }
@@ -174,7 +180,7 @@ class BookmarkFileServiceTest extends TestCase
         $this->assertEquals($updated, $bookmark->getUpdated());
 
         // reload from file
-        $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true);
+        $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
 
         $bookmark = $this->privateLinkDB->get(43);
         $this->assertEquals(43, $bookmark->getId());
@@ -212,7 +218,7 @@ class BookmarkFileServiceTest extends TestCase
         $this->assertNull($bookmark->getUpdated());
 
         // reload from file
-        $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true);
+        $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
 
         $bookmark = $this->privateLinkDB->get(43);
         $this->assertEquals(43, $bookmark->getId());
@@ -242,7 +248,7 @@ class BookmarkFileServiceTest extends TestCase
         $this->assertEquals(43, $bookmark->getId());
 
         // reload from file
-        $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true);
+        $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
 
         $this->privateLinkDB->get(43);
     }
@@ -314,7 +320,7 @@ class BookmarkFileServiceTest extends TestCase
         $this->assertTrue(new \DateTime('5 seconds ago') < $bookmark->getUpdated());
 
         // reload from file
-        $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true);
+        $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
 
         $bookmark = $this->privateLinkDB->get(42);
         $this->assertEquals(42, $bookmark->getId());
@@ -355,7 +361,7 @@ class BookmarkFileServiceTest extends TestCase
         $this->assertTrue(new \DateTime('5 seconds ago') < $bookmark->getUpdated());
 
         // reload from file
-        $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true);
+        $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
 
         $bookmark = $this->privateLinkDB->get(42);
         $this->assertEquals(42, $bookmark->getId());
@@ -388,7 +394,7 @@ class BookmarkFileServiceTest extends TestCase
         $this->assertEquals($title, $bookmark->getTitle());
 
         // reload from file
-        $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true);
+        $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
 
         $bookmark = $this->privateLinkDB->get(42);
         $this->assertEquals(42, $bookmark->getId());
@@ -452,7 +458,7 @@ class BookmarkFileServiceTest extends TestCase
         $this->assertEquals(43, $bookmark->getId());
 
         // reload from file
-        $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true);
+        $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
 
         $bookmark = $this->privateLinkDB->get(43);
         $this->assertEquals(43, $bookmark->getId());
@@ -472,7 +478,7 @@ class BookmarkFileServiceTest extends TestCase
         $this->assertEquals($title, $bookmark->getTitle());
 
         // reload from file
-        $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true);
+        $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
 
         $bookmark = $this->privateLinkDB->get(42);
         $this->assertEquals(42, $bookmark->getId());
@@ -515,7 +521,7 @@ class BookmarkFileServiceTest extends TestCase
         $this->assertEquals($title, $bookmark->getTitle());
 
         // reload from file
-        $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true);
+        $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
 
         $bookmark = $this->privateLinkDB->get(42);
         $this->assertEquals(42, $bookmark->getId());
@@ -541,7 +547,7 @@ class BookmarkFileServiceTest extends TestCase
         $this->assertInstanceOf(BookmarkNotFoundException::class, $exception);
 
         // reload from file
-        $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true);
+        $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
 
         $this->privateLinkDB->get(42);
     }
@@ -645,7 +651,7 @@ class BookmarkFileServiceTest extends TestCase
 
         $conf = new ConfigManager('tests/utils/config/configJson');
         $conf->set('resource.datastore', 'null/store.db');
-        new BookmarkFileService($conf, $this->history, true);
+        new BookmarkFileService($conf, $this->history, $this->mutex, true);
     }
 
     /**
@@ -655,7 +661,7 @@ class BookmarkFileServiceTest extends TestCase
     {
         unlink(self::$testDatastore);
         $this->assertFileNotExists(self::$testDatastore);
-        new BookmarkFileService($this->conf, $this->history, true);
+        new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
         $this->assertFileExists(self::$testDatastore);
 
         // ensure the correct data has been written
@@ -669,7 +675,7 @@ class BookmarkFileServiceTest extends TestCase
     {
         unlink(self::$testDatastore);
         $this->assertFileNotExists(self::$testDatastore);
-        $db = new \FakeBookmarkService($this->conf, $this->history, false);
+        $db = new \FakeBookmarkService($this->conf, $this->history, $this->mutex, false);
         $this->assertFileNotExists(self::$testDatastore);
         $this->assertInstanceOf(BookmarkArray::class, $db->getBookmarks());
         $this->assertCount(0, $db->getBookmarks());
@@ -702,13 +708,13 @@ class BookmarkFileServiceTest extends TestCase
      */
     public function testSave()
     {
-        $testDB = new BookmarkFileService($this->conf, $this->history, true);
+        $testDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
         $dbSize = $testDB->count();
 
         $bookmark = new Bookmark();
         $testDB->add($bookmark);
 
-        $testDB = new BookmarkFileService($this->conf, $this->history, true);
+        $testDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
         $this->assertEquals($dbSize + 1, $testDB->count());
     }
 
@@ -718,7 +724,7 @@ class BookmarkFileServiceTest extends TestCase
     public function testCountHiddenPublic()
     {
         $this->conf->set('privacy.hide_public_links', true);
-        $linkDB = new BookmarkFileService($this->conf, $this->history, false);
+        $linkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, false);
 
         $this->assertEquals(0, $linkDB->count());
     }
index 48c7f8247bc02ca32900886e7f7d86aac90027c8..644abbc8429f18b51c64c6a64a6cac7d50fc7598 100644 (file)
@@ -3,6 +3,7 @@
 namespace Shaarli\Bookmark;
 
 use Exception;
+use malkusch\lock\mutex\NoMutex;
 use ReferenceLinkDB;
 use Shaarli\Config\ConfigManager;
 use Shaarli\History;
@@ -37,12 +38,13 @@ class BookmarkFilterTest extends TestCase
      */
     public static function setUpBeforeClass(): void
     {
+        $mutex = new NoMutex();
         $conf = new ConfigManager('tests/utils/config/configJson');
         $conf->set('resource.datastore', self::$testDatastore);
         self::$refDB = new \ReferenceLinkDB();
         self::$refDB->write(self::$testDatastore);
         $history = new History('sandbox/history.php');
-        self::$bookmarkService = new \FakeBookmarkService($conf, $history, true);
+        self::$bookmarkService = new \FakeBookmarkService($conf, $history, $mutex, true);
         self::$linkFilter = new BookmarkFilter(self::$bookmarkService->getBookmarks());
     }
 
index 25704004e8909f9d1d8e3878d1e2043e571f66ce..0c8420ce5ffceac84e4dd471cdc8f8fa567113d1 100644 (file)
@@ -2,6 +2,7 @@
 
 namespace Shaarli\Bookmark;
 
+use malkusch\lock\mutex\NoMutex;
 use Shaarli\Config\ConfigManager;
 use Shaarli\History;
 use Shaarli\TestCase;
@@ -34,11 +35,15 @@ class BookmarkInitializerTest extends TestCase
     /** @var BookmarkInitializer instance */
     protected $initializer;
 
+    /** @var NoMutex */
+    protected $mutex;
+
     /**
      * Initialize an empty BookmarkFileService
      */
     public function setUp(): void
     {
+        $this->mutex = new NoMutex();
         if (file_exists(self::$testDatastore)) {
             unlink(self::$testDatastore);
         }
@@ -47,7 +52,7 @@ class BookmarkInitializerTest extends TestCase
         $this->conf = new ConfigManager(self::$testConf);
         $this->conf->set('resource.datastore', self::$testDatastore);
         $this->history = new History('sandbox/history.php');
-        $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true);
+        $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
 
         $this->initializer = new BookmarkInitializer($this->bookmarkService);
     }
@@ -59,7 +64,7 @@ class BookmarkInitializerTest extends TestCase
     {
         $refDB = new \ReferenceLinkDB();
         $refDB->write(self::$testDatastore);
-        $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true);
+        $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
         $this->initializer = new BookmarkInitializer($this->bookmarkService);
 
         $this->initializer->initialize();
@@ -90,7 +95,7 @@ class BookmarkInitializerTest extends TestCase
         $this->bookmarkService->save();
 
         // Reload from file
-        $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true);
+        $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
         $this->assertEquals($refDB->countLinks() + 3, $this->bookmarkService->count());
 
         $bookmark = $this->bookmarkService->get(43);
@@ -121,7 +126,7 @@ class BookmarkInitializerTest extends TestCase
     public function testInitializeNonExistentDataStore(): void
     {
         $this->conf->set('resource.datastore', static::$testDatastore . '_empty');
-        $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true);
+        $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
 
         $this->initializer->initialize();
 
index 2d675c9a006d9ab24f1e4e522df8f5a7e7de476e..3508a7b170d1572b017120b1966f911ed9f7892f 100644 (file)
@@ -30,3 +30,7 @@ require_once 'tests/utils/ReferenceLinkDB.php';
 require_once 'tests/utils/ReferenceSessionIdHashes.php';
 
 \ReferenceSessionIdHashes::genAllHashes();
+
+if (!defined('SHAARLI_MUTEX_FILE')) {
+    define('SHAARLI_MUTEX_FILE', __FILE__);
+}
index c29e8ef3b01753b42f3cb37544cb49c165439a67..6b9204eb64949cb17ada2c26bf605e7f9a3373a4 100644 (file)
@@ -3,6 +3,7 @@
 namespace Shaarli\Feed;
 
 use DateTime;
+use malkusch\lock\mutex\NoMutex;
 use ReferenceLinkDB;
 use Shaarli\Bookmark\Bookmark;
 use Shaarli\Bookmark\BookmarkFileService;
@@ -47,6 +48,7 @@ class FeedBuilderTest extends TestCase
      */
     public static function setUpBeforeClass(): void
     {
+        $mutex = new NoMutex();
         $conf = new ConfigManager('tests/utils/config/configJson');
         $conf->set('resource.datastore', self::$testDatastore);
         $refLinkDB = new \ReferenceLinkDB();
@@ -54,7 +56,7 @@ class FeedBuilderTest extends TestCase
         $history = new History('sandbox/history.php');
         $factory = new FormatterFactory($conf, true);
         self::$formatter = $factory->getFormatter();
-        self::$bookmarkService = new BookmarkFileService($conf, $history, true);
+        self::$bookmarkService = new BookmarkFileService($conf, $history, $mutex, true);
 
         self::$serverInfo = array(
             'HTTPS' => 'Off',
index 9b95ccc9eaf9338fbbed007ef63b1f300450ed6a..ad288f78ef802835f238e8d40f4c6c8d9bd2059d 100644 (file)
@@ -2,6 +2,7 @@
 
 namespace Shaarli\Netscape;
 
+use malkusch\lock\mutex\NoMutex;
 use Shaarli\Bookmark\BookmarkFileService;
 use Shaarli\Config\ConfigManager;
 use Shaarli\Formatter\BookmarkFormatter;
@@ -56,12 +57,13 @@ class BookmarkExportTest extends TestCase
      */
     public static function setUpBeforeClass(): void
     {
+        $mutex = new NoMutex();
         static::$conf = new ConfigManager('tests/utils/config/configJson');
         static::$conf->set('resource.datastore', static::$testDatastore);
         static::$refDb = new \ReferenceLinkDB();
         static::$refDb->write(static::$testDatastore);
         static::$history = new History('sandbox/history.php');
-        static::$bookmarkService = new BookmarkFileService(static::$conf, static::$history, true);
+        static::$bookmarkService = new BookmarkFileService(static::$conf, static::$history, $mutex, true);
         $factory = new FormatterFactory(static::$conf, true);
         static::$formatter = $factory->getFormatter('raw');
     }
index c1e49b5f454584fe0b29272e455e991656d3e8e5..c526d5c8382699c27a57ffbc12622e153c42c4cf 100644 (file)
@@ -3,6 +3,7 @@
 namespace Shaarli\Netscape;
 
 use DateTime;
+use malkusch\lock\mutex\NoMutex;
 use Psr\Http\Message\UploadedFileInterface;
 use Shaarli\Bookmark\Bookmark;
 use Shaarli\Bookmark\BookmarkFileService;
@@ -87,6 +88,7 @@ class BookmarkImportTest extends TestCase
      */
     protected function setUp(): void
     {
+        $mutex = new NoMutex();
         if (file_exists(self::$testDatastore)) {
             unlink(self::$testDatastore);
         }
@@ -97,7 +99,7 @@ class BookmarkImportTest extends TestCase
         $this->conf->set('resource.page_cache', $this->pagecache);
         $this->conf->set('resource.datastore', self::$testDatastore);
         $this->history = new History(self::$historyFilePath);
-        $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true);
+        $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $mutex, true);
         $this->netscapeBookmarkUtils = new NetscapeBookmarkUtils($this->bookmarkService, $this->conf, $this->history);
     }
 
index a6280b8c9b911a8d3b33ac0d4af2684304a49256..47332544a7b254c8a56ab4adf6c80604daad5ac5 100644 (file)
@@ -2,6 +2,7 @@
 namespace Shaarli\Updater;
 
 use Exception;
+use malkusch\lock\mutex\NoMutex;
 use Shaarli\Bookmark\BookmarkFileService;
 use Shaarli\Bookmark\BookmarkServiceInterface;
 use Shaarli\Config\ConfigManager;
@@ -44,12 +45,13 @@ class UpdaterTest extends TestCase
      */
     protected function setUp(): void
     {
+        $mutex = new NoMutex();
         $this->refDB = new \ReferenceLinkDB();
         $this->refDB->write(self::$testDatastore);
 
         copy('tests/utils/config/configJson.json.php', self::$configFile .'.json.php');
         $this->conf = new ConfigManager(self::$configFile);
-        $this->bookmarkService = new BookmarkFileService($this->conf, $this->createMock(History::class), true);
+        $this->bookmarkService = new BookmarkFileService($this->conf, $this->createMock(History::class), $mutex, true);
         $this->updater = new Updater([], $this->bookmarkService, $this->conf, true);
     }