Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
47.06% |
16 / 34 |
|
20.00% |
1 / 5 |
CRAP | |
0.00% |
0 / 1 |
SwiftFileBackendList | |
47.06% |
16 / 34 |
|
20.00% |
1 / 5 |
28.95 | |
0.00% |
0 / 1 |
__construct | |
77.78% |
7 / 9 |
|
0.00% |
0 / 1 |
3.10 | |||
key | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
next | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
20 | |||
rewind | |
100.00% |
9 / 9 |
|
100.00% |
1 / 1 |
1 | |||
valid | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
pageFromList | n/a |
0 / 0 |
n/a |
0 / 0 |
0 |
1 | <?php |
2 | /** |
3 | * OpenStack Swift based file backend. |
4 | * |
5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by |
7 | * the Free Software Foundation; either version 2 of the License, or |
8 | * (at your option) any later version. |
9 | * |
10 | * This program is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | * GNU General Public License for more details. |
14 | * |
15 | * You should have received a copy of the GNU General Public License along |
16 | * with this program; if not, write to the Free Software Foundation, Inc., |
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
18 | * http://www.gnu.org/copyleft/gpl.html |
19 | * |
20 | * @file |
21 | * @ingroup FileBackend |
22 | * @author Russ Nelson |
23 | */ |
24 | |
25 | /** |
26 | * SwiftFileBackend helper class to page through listings. |
27 | * Swift also has a listing limit of 10,000 objects for performance. |
28 | * Do not use this class from places outside SwiftFileBackend. |
29 | * |
30 | * @ingroup FileBackend |
31 | */ |
32 | abstract class SwiftFileBackendList implements Iterator { |
33 | /** @var string[]|array[] Current page of entries; path list or (path,stat map) list */ |
34 | protected $iterableBuffer = []; |
35 | |
36 | /** @var string|null Continuation marker; the next page starts *after* this path */ |
37 | protected $continueAfter = null; |
38 | |
39 | /** @var int */ |
40 | protected $pos = 0; |
41 | |
42 | /** @var array */ |
43 | protected $params = []; |
44 | |
45 | /** @var SwiftFileBackend */ |
46 | protected $backend; |
47 | |
48 | /** @var string Container name */ |
49 | protected $container; |
50 | |
51 | /** @var string Storage directory */ |
52 | protected $dir; |
53 | |
54 | /** @var int */ |
55 | protected $suffixStart; |
56 | |
57 | private const PAGE_SIZE = 9000; // file listing buffer size |
58 | |
59 | /** |
60 | * @param SwiftFileBackend $backend |
61 | * @param string $fullCont Resolved container name |
62 | * @param string $dir Resolved directory relative to container |
63 | * @param array $params |
64 | * @note This defers I/O by not buffering the first page (useful for AppendIterator use) |
65 | * @note Do not call current()/valid() without calling rewind() first |
66 | */ |
67 | public function __construct( SwiftFileBackend $backend, $fullCont, $dir, array $params ) { |
68 | $this->backend = $backend; |
69 | $this->container = $fullCont; |
70 | $this->dir = $dir; |
71 | if ( substr( $this->dir, -1 ) === '/' ) { |
72 | $this->dir = substr( $this->dir, 0, -1 ); // remove trailing slash |
73 | } |
74 | if ( $this->dir == '' ) { // whole container |
75 | $this->suffixStart = 0; |
76 | } else { // dir within container |
77 | $this->suffixStart = strlen( $this->dir ) + 1; // size of "path/to/dir/" |
78 | } |
79 | $this->params = $params; |
80 | } |
81 | |
82 | /** |
83 | * @see Iterator::key() |
84 | * @return int |
85 | */ |
86 | public function key(): int { |
87 | return $this->pos; |
88 | } |
89 | |
90 | /** |
91 | * @inheritDoc |
92 | */ |
93 | public function next(): void { |
94 | ++$this->pos; |
95 | if ( $this->iterableBuffer === null ) { |
96 | // Last page of entries failed to load |
97 | return; |
98 | } |
99 | // Advance to the next entry in the page |
100 | next( $this->iterableBuffer ); |
101 | // Check if there are no entries left in this page and |
102 | // advance to the next page if this page was not empty. |
103 | if ( !$this->valid() && count( $this->iterableBuffer ) ) { |
104 | $this->iterableBuffer = $this->pageFromList( |
105 | $this->container, |
106 | $this->dir, |
107 | $this->continueAfter, |
108 | self::PAGE_SIZE, |
109 | $this->params |
110 | ); |
111 | } |
112 | } |
113 | |
114 | /** |
115 | * @inheritDoc |
116 | */ |
117 | public function rewind(): void { |
118 | $this->pos = 0; |
119 | $this->continueAfter = null; |
120 | $this->iterableBuffer = $this->pageFromList( |
121 | $this->container, |
122 | $this->dir, |
123 | // @phan-suppress-next-line PhanTypeMismatchArgumentPropertyReferenceReal |
124 | $this->continueAfter, |
125 | self::PAGE_SIZE, |
126 | $this->params |
127 | ); |
128 | } |
129 | |
130 | /** |
131 | * @see Iterator::valid() |
132 | * @return bool |
133 | */ |
134 | public function valid(): bool { |
135 | if ( $this->iterableBuffer === null ) { |
136 | // Last page of entries failed to load |
137 | return false; |
138 | } |
139 | // Note that entries (paths/tuples) are never boolean |
140 | return ( current( $this->iterableBuffer ) !== false ); |
141 | } |
142 | |
143 | /** |
144 | * Get the next page of entries |
145 | * |
146 | * @param string $container Resolved container name |
147 | * @param string $dir Resolved path relative to container |
148 | * @param string &$after @phan-output-reference Continuation marker |
149 | * @param int $limit |
150 | * @param array $params |
151 | * @return Traversable|array |
152 | */ |
153 | abstract protected function pageFromList( $container, $dir, &$after, $limit, array $params ); |
154 | } |