Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
73.77% covered (warning)
73.77%
45 / 61
57.14% covered (warning)
57.14%
8 / 14
CRAP
0.00% covered (danger)
0.00%
0 / 1
JobQueueMemory
73.77% covered (warning)
73.77%
45 / 61
57.14% covered (warning)
57.14%
8 / 14
42.15
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 doBatchPush
57.14% covered (warning)
57.14%
4 / 7
0.00% covered (danger)
0.00%
0 / 1
5.26
 supportedOrders
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 optimalOrder
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 doIsEmpty
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 doGetSize
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 doGetAcquiredCount
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
 doPop
84.62% covered (warning)
84.62%
11 / 13
0.00% covered (danger)
0.00%
0 / 1
3.03
 doAck
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 doDelete
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
12
 getAllQueuedJobs
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
2
 getAllAcquiredJobs
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
2
 jobFromSpecInternal
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getQueueData
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2/**
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 * http://www.gnu.org/copyleft/gpl.html
17 *
18 * @file
19 */
20
21use Wikimedia\ObjectCache\HashBagOStuff;
22
23/**
24 * PHP memory-backed job queue storage, for testing.
25 *
26 * JobQueueGroup does not remember every queue instance, so statically track it here.
27 *
28 * @since 1.27
29 * @ingroup JobQueue
30 */
31class JobQueueMemory extends JobQueue {
32    /** @var array[] */
33    protected static $data = [];
34
35    public function __construct( array $params ) {
36        $params['wanCache'] = new WANObjectCache( [ 'cache' => new HashBagOStuff() ] );
37
38        parent::__construct( $params );
39    }
40
41    /**
42     * @see JobQueue::doBatchPush
43     *
44     * @param IJobSpecification[] $jobs
45     * @param int $flags
46     */
47    protected function doBatchPush( array $jobs, $flags ) {
48        $unclaimed =& $this->getQueueData( 'unclaimed', [] );
49
50        foreach ( $jobs as $job ) {
51            if ( $job->ignoreDuplicates() ) {
52                $sha1 = sha1( serialize( $job->getDeduplicationInfo() ) );
53                if ( !isset( $unclaimed[$sha1] ) ) {
54                    $unclaimed[$sha1] = $job;
55                }
56            } else {
57                $unclaimed[] = $job;
58            }
59        }
60    }
61
62    /**
63     * @see JobQueue::supportedOrders
64     *
65     * @return string[]
66     */
67    protected function supportedOrders() {
68        return [ 'random', 'timestamp', 'fifo' ];
69    }
70
71    /**
72     * @see JobQueue::optimalOrder
73     *
74     * @return string
75     */
76    protected function optimalOrder() {
77        return 'fifo';
78    }
79
80    /**
81     * @see JobQueue::doIsEmpty
82     *
83     * @return bool
84     */
85    protected function doIsEmpty() {
86        return ( $this->doGetSize() == 0 );
87    }
88
89    /**
90     * @see JobQueue::doGetSize
91     *
92     * @return int
93     */
94    protected function doGetSize() {
95        $unclaimed = $this->getQueueData( 'unclaimed' );
96
97        return $unclaimed ? count( $unclaimed ) : 0;
98    }
99
100    /**
101     * @see JobQueue::doGetAcquiredCount
102     *
103     * @return int
104     */
105    protected function doGetAcquiredCount() {
106        $claimed = $this->getQueueData( 'claimed' );
107
108        return $claimed ? count( $claimed ) : 0;
109    }
110
111    /**
112     * @see JobQueue::doPop
113     *
114     * @return RunnableJob|false
115     */
116    protected function doPop() {
117        if ( $this->doGetSize() == 0 ) {
118            return false;
119        }
120
121        $unclaimed =& $this->getQueueData( 'unclaimed' );
122        $claimed =& $this->getQueueData( 'claimed', [] );
123
124        if ( $this->order === 'random' ) {
125            $key = array_rand( $unclaimed );
126        } else {
127            $key = array_key_first( $unclaimed );
128        }
129
130        $spec = $unclaimed[$key];
131        unset( $unclaimed[$key] );
132        $claimed[] = $spec;
133
134        $job = $this->jobFromSpecInternal( $spec );
135
136        $job->setMetadata( 'claimId', array_key_last( $claimed ) );
137
138        return $job;
139    }
140
141    /**
142     * @see JobQueue::doAck
143     *
144     * @param RunnableJob $job
145     */
146    protected function doAck( RunnableJob $job ) {
147        if ( $this->getAcquiredCount() == 0 ) {
148            return;
149        }
150
151        $claimed =& $this->getQueueData( 'claimed' );
152        unset( $claimed[$job->getMetadata( 'claimId' )] );
153    }
154
155    /**
156     * @inheritDoc
157     */
158    protected function doDelete() {
159        if ( isset( self::$data[$this->type][$this->domain] ) ) {
160            unset( self::$data[$this->type][$this->domain] );
161            if ( !self::$data[$this->type] ) {
162                unset( self::$data[$this->type] );
163            }
164        }
165    }
166
167    /**
168     * @see JobQueue::getAllQueuedJobs
169     *
170     * @return Iterator<RunnableJob> of Job objects.
171     */
172    public function getAllQueuedJobs() {
173        $unclaimed = $this->getQueueData( 'unclaimed' );
174        if ( !$unclaimed ) {
175            return new ArrayIterator( [] );
176        }
177
178        return new MappedIterator(
179            $unclaimed,
180            function ( $value ) {
181                return $this->jobFromSpecInternal( $value );
182            }
183        );
184    }
185
186    /**
187     * @see JobQueue::getAllAcquiredJobs
188     *
189     * @return Iterator<RunnableJob> of Job objects.
190     */
191    public function getAllAcquiredJobs() {
192        $claimed = $this->getQueueData( 'claimed' );
193        if ( !$claimed ) {
194            return new ArrayIterator( [] );
195        }
196
197        return new MappedIterator(
198            $claimed,
199            function ( $value ) {
200                return $this->jobFromSpecInternal( $value );
201            }
202        );
203    }
204
205    /**
206     * @param IJobSpecification $spec
207     * @return RunnableJob
208     */
209    public function jobFromSpecInternal( IJobSpecification $spec ) {
210        return $this->factoryJob( $spec->getType(), $spec->getParams() );
211    }
212
213    /**
214     * @param string $field
215     * @param mixed|null $init
216     *
217     * @return mixed
218     */
219    private function &getQueueData( $field, $init = null ) {
220        if ( !isset( self::$data[$this->type][$this->domain][$field] ) ) {
221            if ( $init !== null ) {
222                self::$data[$this->type][$this->domain][$field] = $init;
223            } else {
224                return $init;
225            }
226        }
227
228        return self::$data[$this->type][$this->domain][$field];
229    }
230}