Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
47.06% covered (danger)
47.06%
16 / 34
20.00% covered (danger)
20.00%
1 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
SwiftFileBackendList
47.06% covered (danger)
47.06%
16 / 34
20.00% covered (danger)
20.00%
1 / 5
28.95
0.00% covered (danger)
0.00%
0 / 1
 __construct
77.78% covered (warning)
77.78%
7 / 9
0.00% covered (danger)
0.00%
0 / 1
3.10
 key
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 next
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
20
 rewind
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
1
 valid
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
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 */
32abstract 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}