|
32 | 32 |
|
33 | 33 | use OCP\AppFramework\Db\TTransactional; |
34 | 34 | use OCP\AppFramework\Http; |
| 35 | +use OCP\DB\Exception; |
35 | 36 | use OCP\IDBConnection; |
36 | 37 | use OCP\IUser; |
37 | 38 | use OCP\IUserManager; |
|
41 | 42 | use Sabre\DAV\Xml\Service; |
42 | 43 | use Sabre\HTTP\ClientHttpException; |
43 | 44 | use Sabre\VObject\Reader; |
| 45 | +use Throwable; |
44 | 46 | use function is_null; |
45 | 47 |
|
46 | 48 | class SyncService { |
@@ -116,15 +118,33 @@ public function syncRemoteAddressBook(string $url, string $userName, string $add |
116 | 118 | * @throws \Sabre\DAV\Exception\BadRequest |
117 | 119 | */ |
118 | 120 | public function ensureSystemAddressBookExists(string $principal, string $uri, array $properties): ?array { |
119 | | - return $this->atomic(function () use ($principal, $uri, $properties) { |
120 | | - $book = $this->backend->getAddressBooksByUri($principal, $uri); |
121 | | - if (!is_null($book)) { |
122 | | - return $book; |
| 121 | + try { |
| 122 | + return $this->atomic(function () use ($principal, $uri, $properties) { |
| 123 | + $book = $this->backend->getAddressBooksByUri($principal, $uri); |
| 124 | + if (!is_null($book)) { |
| 125 | + return $book; |
| 126 | + } |
| 127 | + $this->backend->createAddressBook($principal, $uri, $properties); |
| 128 | + |
| 129 | + return $this->backend->getAddressBooksByUri($principal, $uri); |
| 130 | + }, $this->dbConnection); |
| 131 | + } catch (Exception $e) { |
| 132 | + // READ COMMITTED doesn't prevent a nonrepeatable read above, so |
| 133 | + // two processes might create an address book here. Ignore our |
| 134 | + // failure and continue loading the entry written by the other process |
| 135 | + if ($e->getReason() !== Exception::REASON_UNIQUE_CONSTRAINT_VIOLATION) { |
| 136 | + throw $e; |
123 | 137 | } |
124 | | - $this->backend->createAddressBook($principal, $uri, $properties); |
125 | 138 |
|
126 | | - return $this->backend->getAddressBooksByUri($principal, $uri); |
127 | | - }, $this->dbConnection); |
| 139 | + // If this fails we might have hit a replication node that does not |
| 140 | + // have the row written in the other process. |
| 141 | + // TODO: find an elegant way to handle this |
| 142 | + $ab = $this->backend->getAddressBooksByUri($principal, $uri); |
| 143 | + if ($ab === null) { |
| 144 | + throw new Exception('Could not create system address book', $e->getCode(), $e); |
| 145 | + } |
| 146 | + return $ab; |
| 147 | + } |
128 | 148 | } |
129 | 149 |
|
130 | 150 | /** |
|
0 commit comments