Completed
Push — stable13 ( cebd51...71ceec )
by Morris
11:29
created
lib/private/Files/Cache/Propagator.php 1 patch
Indentation   +155 added lines, -155 removed lines patch added patch discarded remove patch
@@ -31,161 +31,161 @@
 block discarded – undo
31 31
  * Propagate etags and mtimes within the storage
32 32
  */
33 33
 class Propagator implements IPropagator {
34
-	private $inBatch = false;
35
-
36
-	private $batch = [];
37
-
38
-	/**
39
-	 * @var \OC\Files\Storage\Storage
40
-	 */
41
-	protected $storage;
42
-
43
-	/**
44
-	 * @var IDBConnection
45
-	 */
46
-	private $connection;
47
-
48
-	/**
49
-	 * @param \OC\Files\Storage\Storage $storage
50
-	 * @param IDBConnection $connection
51
-	 */
52
-	public function __construct(\OC\Files\Storage\Storage $storage, IDBConnection $connection) {
53
-		$this->storage = $storage;
54
-		$this->connection = $connection;
55
-	}
56
-
57
-
58
-	/**
59
-	 * @param string $internalPath
60
-	 * @param int $time
61
-	 * @param int $sizeDifference number of bytes the file has grown
62
-	 * @suppress SqlInjectionChecker
63
-	 */
64
-	public function propagateChange($internalPath, $time, $sizeDifference = 0) {
65
-		$storageId = (int)$this->storage->getStorageCache()->getNumericId();
66
-
67
-		$parents = $this->getParents($internalPath);
68
-
69
-		if ($this->inBatch) {
70
-			foreach ($parents as $parent) {
71
-				$this->addToBatch($parent, $time, $sizeDifference);
72
-			}
73
-			return;
74
-		}
75
-
76
-		$parentHashes = array_map('md5', $parents);
77
-		$etag = uniqid(); // since we give all folders the same etag we don't ask the storage for the etag
78
-
79
-		$builder = $this->connection->getQueryBuilder();
80
-		$hashParams = array_map(function ($hash) use ($builder) {
81
-			return $builder->expr()->literal($hash);
82
-		}, $parentHashes);
83
-
84
-		$builder->update('filecache')
85
-			->set('mtime', $builder->createFunction('GREATEST(`mtime`, ' . $builder->createNamedParameter((int)$time, IQueryBuilder::PARAM_INT) . ')'))
86
-			->set('etag', $builder->createNamedParameter($etag, IQueryBuilder::PARAM_STR))
87
-			->where($builder->expr()->eq('storage', $builder->createNamedParameter($storageId, IQueryBuilder::PARAM_INT)))
88
-			->andWhere($builder->expr()->in('path_hash', $hashParams));
89
-
90
-		$builder->execute();
91
-
92
-		if ($sizeDifference !== 0) {
93
-			// we need to do size separably so we can ignore entries with uncalculated size
94
-			$builder = $this->connection->getQueryBuilder();
95
-			$builder->update('filecache')
96
-				->set('size', $builder->createFunction('`size` + ' . $builder->createNamedParameter($sizeDifference)))
97
-				->where($builder->expr()->eq('storage', $builder->createNamedParameter($storageId, IQueryBuilder::PARAM_INT)))
98
-				->andWhere($builder->expr()->in('path_hash', $hashParams))
99
-				->andWhere($builder->expr()->gt('size', $builder->expr()->literal(-1, IQueryBuilder::PARAM_INT)));
100
-
101
-			$builder->execute();
102
-		}
103
-	}
104
-
105
-	protected function getParents($path) {
106
-		$parts = explode('/', $path);
107
-		$parent = '';
108
-		$parents = [];
109
-		foreach ($parts as $part) {
110
-			$parents[] = $parent;
111
-			$parent = trim($parent . '/' . $part, '/');
112
-		}
113
-		return $parents;
114
-	}
115
-
116
-	/**
117
-	 * Mark the beginning of a propagation batch
118
-	 *
119
-	 * Note that not all cache setups support propagation in which case this will be a noop
120
-	 *
121
-	 * Batching for cache setups that do support it has to be explicit since the cache state is not fully consistent
122
-	 * before the batch is committed.
123
-	 */
124
-	public function beginBatch() {
125
-		$this->inBatch = true;
126
-	}
127
-
128
-	private function addToBatch($internalPath, $time, $sizeDifference) {
129
-		if (!isset($this->batch[$internalPath])) {
130
-			$this->batch[$internalPath] = [
131
-				'hash' => md5($internalPath),
132
-				'time' => $time,
133
-				'size' => $sizeDifference
134
-			];
135
-		} else {
136
-			$this->batch[$internalPath]['size'] += $sizeDifference;
137
-			if ($time > $this->batch[$internalPath]['time']) {
138
-				$this->batch[$internalPath]['time'] = $time;
139
-			}
140
-		}
141
-	}
142
-
143
-	/**
144
-	 * Commit the active propagation batch
145
-	 * @suppress SqlInjectionChecker
146
-	 */
147
-	public function commitBatch() {
148
-		if (!$this->inBatch) {
149
-			throw new \BadMethodCallException('Not in batch');
150
-		}
151
-		$this->inBatch = false;
152
-
153
-		$this->connection->beginTransaction();
154
-
155
-		$query = $this->connection->getQueryBuilder();
156
-		$storageId = (int)$this->storage->getStorageCache()->getNumericId();
157
-
158
-		$query->update('filecache')
159
-			->set('mtime', $query->createFunction('GREATEST(`mtime`, ' . $query->createParameter('time') . ')'))
160
-			->set('etag', $query->expr()->literal(uniqid()))
161
-			->where($query->expr()->eq('storage', $query->expr()->literal($storageId, IQueryBuilder::PARAM_INT)))
162
-			->andWhere($query->expr()->eq('path_hash', $query->createParameter('hash')));
163
-
164
-		$sizeQuery = $this->connection->getQueryBuilder();
165
-		$sizeQuery->update('filecache')
166
-			->set('size', $sizeQuery->createFunction('`size` + ' . $sizeQuery->createParameter('size')))
167
-			->where($query->expr()->eq('storage', $query->expr()->literal($storageId, IQueryBuilder::PARAM_INT)))
168
-			->andWhere($query->expr()->eq('path_hash', $query->createParameter('hash')))
169
-			->andWhere($sizeQuery->expr()->gt('size', $sizeQuery->expr()->literal(-1, IQueryBuilder::PARAM_INT)));
170
-
171
-		foreach ($this->batch as $item) {
172
-			$query->setParameter('time', $item['time'], IQueryBuilder::PARAM_INT);
173
-			$query->setParameter('hash', $item['hash']);
174
-
175
-			$query->execute();
176
-
177
-			if ($item['size']) {
178
-				$sizeQuery->setParameter('size', $item['size'], IQueryBuilder::PARAM_INT);
179
-				$sizeQuery->setParameter('hash', $item['hash']);
180
-
181
-				$sizeQuery->execute();
182
-			}
183
-		}
184
-
185
-		$this->batch = [];
186
-
187
-		$this->connection->commit();
188
-	}
34
+    private $inBatch = false;
35
+
36
+    private $batch = [];
37
+
38
+    /**
39
+     * @var \OC\Files\Storage\Storage
40
+     */
41
+    protected $storage;
42
+
43
+    /**
44
+     * @var IDBConnection
45
+     */
46
+    private $connection;
47
+
48
+    /**
49
+     * @param \OC\Files\Storage\Storage $storage
50
+     * @param IDBConnection $connection
51
+     */
52
+    public function __construct(\OC\Files\Storage\Storage $storage, IDBConnection $connection) {
53
+        $this->storage = $storage;
54
+        $this->connection = $connection;
55
+    }
56
+
57
+
58
+    /**
59
+     * @param string $internalPath
60
+     * @param int $time
61
+     * @param int $sizeDifference number of bytes the file has grown
62
+     * @suppress SqlInjectionChecker
63
+     */
64
+    public function propagateChange($internalPath, $time, $sizeDifference = 0) {
65
+        $storageId = (int)$this->storage->getStorageCache()->getNumericId();
66
+
67
+        $parents = $this->getParents($internalPath);
68
+
69
+        if ($this->inBatch) {
70
+            foreach ($parents as $parent) {
71
+                $this->addToBatch($parent, $time, $sizeDifference);
72
+            }
73
+            return;
74
+        }
75
+
76
+        $parentHashes = array_map('md5', $parents);
77
+        $etag = uniqid(); // since we give all folders the same etag we don't ask the storage for the etag
78
+
79
+        $builder = $this->connection->getQueryBuilder();
80
+        $hashParams = array_map(function ($hash) use ($builder) {
81
+            return $builder->expr()->literal($hash);
82
+        }, $parentHashes);
83
+
84
+        $builder->update('filecache')
85
+            ->set('mtime', $builder->createFunction('GREATEST(`mtime`, ' . $builder->createNamedParameter((int)$time, IQueryBuilder::PARAM_INT) . ')'))
86
+            ->set('etag', $builder->createNamedParameter($etag, IQueryBuilder::PARAM_STR))
87
+            ->where($builder->expr()->eq('storage', $builder->createNamedParameter($storageId, IQueryBuilder::PARAM_INT)))
88
+            ->andWhere($builder->expr()->in('path_hash', $hashParams));
89
+
90
+        $builder->execute();
91
+
92
+        if ($sizeDifference !== 0) {
93
+            // we need to do size separably so we can ignore entries with uncalculated size
94
+            $builder = $this->connection->getQueryBuilder();
95
+            $builder->update('filecache')
96
+                ->set('size', $builder->createFunction('`size` + ' . $builder->createNamedParameter($sizeDifference)))
97
+                ->where($builder->expr()->eq('storage', $builder->createNamedParameter($storageId, IQueryBuilder::PARAM_INT)))
98
+                ->andWhere($builder->expr()->in('path_hash', $hashParams))
99
+                ->andWhere($builder->expr()->gt('size', $builder->expr()->literal(-1, IQueryBuilder::PARAM_INT)));
100
+
101
+            $builder->execute();
102
+        }
103
+    }
104
+
105
+    protected function getParents($path) {
106
+        $parts = explode('/', $path);
107
+        $parent = '';
108
+        $parents = [];
109
+        foreach ($parts as $part) {
110
+            $parents[] = $parent;
111
+            $parent = trim($parent . '/' . $part, '/');
112
+        }
113
+        return $parents;
114
+    }
115
+
116
+    /**
117
+     * Mark the beginning of a propagation batch
118
+     *
119
+     * Note that not all cache setups support propagation in which case this will be a noop
120
+     *
121
+     * Batching for cache setups that do support it has to be explicit since the cache state is not fully consistent
122
+     * before the batch is committed.
123
+     */
124
+    public function beginBatch() {
125
+        $this->inBatch = true;
126
+    }
127
+
128
+    private function addToBatch($internalPath, $time, $sizeDifference) {
129
+        if (!isset($this->batch[$internalPath])) {
130
+            $this->batch[$internalPath] = [
131
+                'hash' => md5($internalPath),
132
+                'time' => $time,
133
+                'size' => $sizeDifference
134
+            ];
135
+        } else {
136
+            $this->batch[$internalPath]['size'] += $sizeDifference;
137
+            if ($time > $this->batch[$internalPath]['time']) {
138
+                $this->batch[$internalPath]['time'] = $time;
139
+            }
140
+        }
141
+    }
142
+
143
+    /**
144
+     * Commit the active propagation batch
145
+     * @suppress SqlInjectionChecker
146
+     */
147
+    public function commitBatch() {
148
+        if (!$this->inBatch) {
149
+            throw new \BadMethodCallException('Not in batch');
150
+        }
151
+        $this->inBatch = false;
152
+
153
+        $this->connection->beginTransaction();
154
+
155
+        $query = $this->connection->getQueryBuilder();
156
+        $storageId = (int)$this->storage->getStorageCache()->getNumericId();
157
+
158
+        $query->update('filecache')
159
+            ->set('mtime', $query->createFunction('GREATEST(`mtime`, ' . $query->createParameter('time') . ')'))
160
+            ->set('etag', $query->expr()->literal(uniqid()))
161
+            ->where($query->expr()->eq('storage', $query->expr()->literal($storageId, IQueryBuilder::PARAM_INT)))
162
+            ->andWhere($query->expr()->eq('path_hash', $query->createParameter('hash')));
163
+
164
+        $sizeQuery = $this->connection->getQueryBuilder();
165
+        $sizeQuery->update('filecache')
166
+            ->set('size', $sizeQuery->createFunction('`size` + ' . $sizeQuery->createParameter('size')))
167
+            ->where($query->expr()->eq('storage', $query->expr()->literal($storageId, IQueryBuilder::PARAM_INT)))
168
+            ->andWhere($query->expr()->eq('path_hash', $query->createParameter('hash')))
169
+            ->andWhere($sizeQuery->expr()->gt('size', $sizeQuery->expr()->literal(-1, IQueryBuilder::PARAM_INT)));
170
+
171
+        foreach ($this->batch as $item) {
172
+            $query->setParameter('time', $item['time'], IQueryBuilder::PARAM_INT);
173
+            $query->setParameter('hash', $item['hash']);
174
+
175
+            $query->execute();
176
+
177
+            if ($item['size']) {
178
+                $sizeQuery->setParameter('size', $item['size'], IQueryBuilder::PARAM_INT);
179
+                $sizeQuery->setParameter('hash', $item['hash']);
180
+
181
+                $sizeQuery->execute();
182
+            }
183
+        }
184
+
185
+        $this->batch = [];
186
+
187
+        $this->connection->commit();
188
+    }
189 189
 
190 190
 
191 191
 }
Please login to merge, or discard this patch.