Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 35
0.00% covered (danger)
0.00%
0 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
CDBMessageIndex
0.00% covered (danger)
0.00%
0 / 35
0.00% covered (danger)
0.00%
0 / 5
182
0.00% covered (danger)
0.00%
0 / 1
 retrieve
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
12
 getKeys
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
6
 get
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
12
 store
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
6
 getReader
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
12
1<?php
2declare( strict_types = 1 );
3
4namespace MediaWiki\Extension\Translate\MessageLoading;
5
6use Cdb\Reader;
7use Cdb\Writer;
8use MediaWiki\Extension\Translate\Utilities\Utilities;
9
10/**
11 * Storage on CDB files.
12 *
13 * This is improved version of SerializedMessageIndex. It uses CDB files
14 * for storage, which means it provides random access. The CDB files are
15 * about double the size of serialized files (~7M for 50000 keys).
16 *
17 * Loading the whole index is slower than serialized, but about the same
18 * as for database. Suitable for single-server setups where
19 * SerializedMessageIndex is too slow for loading the whole index.
20 */
21class CDBMessageIndex extends MessageIndex {
22    private ?array $index = null;
23    private ?Reader $reader = null;
24    private const FILENAME = 'translate_messageindex.cdb';
25
26    public function retrieve( bool $readLatest = false ): array {
27        $reader = $this->getReader();
28        // This must be below the line above, which may fill the index
29        if ( $this->index !== null ) {
30            return $this->index;
31        }
32
33        $this->index = [];
34        foreach ( $this->getKeys() as $key ) {
35            $this->index[$key] = $this->unserialize( $reader->get( $key ) );
36        }
37
38        return $this->index;
39    }
40
41    public function getKeys(): array {
42        $reader = $this->getReader();
43        $keys = [];
44        $key = $reader->firstkey();
45        while ( $key !== false ) {
46            $keys[] = $key;
47            $key = $reader->nextkey();
48        }
49
50        return $keys;
51    }
52
53    /** @inheritDoc */
54    protected function get( $key ) {
55        $reader = $this->getReader();
56        // We might have the full cache loaded
57        if ( $this->index !== null ) {
58            return $this->index[$key] ?? null;
59        }
60
61        $value = $reader->get( $key );
62        return is_string( $value ) ? $this->unserialize( $value ) : null;
63    }
64
65    /** @inheritDoc */
66    protected function store( array $array, array $diff ): void {
67        $this->reader = null;
68
69        $file = Utilities::cacheFile( self::FILENAME );
70        $cache = Writer::open( $file );
71
72        foreach ( $array as $key => $value ) {
73            $value = $this->serialize( $value );
74            $cache->set( $key, $value );
75        }
76
77        $cache->close();
78
79        $this->index = $array;
80    }
81
82    private function getReader() {
83        if ( $this->reader ) {
84            return $this->reader;
85        }
86
87        $file = Utilities::cacheFile( self::FILENAME );
88        if ( !file_exists( $file ) ) {
89            // Create an empty index to allow rebuild
90            $this->store( [], [] );
91            $this->index = $this->rebuild();
92        }
93
94        $this->reader = Reader::open( $file );
95        return $this->reader;
96    }
97}