Skip to content

Commit 7135b61

Browse files
committed
Merge branch 'master' into dev-1.2
2 parents 1674332 + 8baa03c commit 7135b61

File tree

9 files changed

+156
-62
lines changed

9 files changed

+156
-62
lines changed

.github/workflows/ci.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515
steps:
1616
- uses: actions/checkout@v4
1717
- name: Cache Composer dependencies
18-
uses: actions/cache@v3
18+
uses: actions/cache@v4
1919
with:
2020
path: /tmp/composer-cache
2121
key: ${{ runner.os }}-${{ hashFiles('**/composer.lock') }}
@@ -34,7 +34,7 @@ jobs:
3434
uses: actions/checkout@v4
3535

3636
- name: Psalm
37-
uses: docker://ghcr.io/psalm/psalm-github-actions
37+
uses: docker://ghcr.io/psalm/psalm-github-actions:6.4.1
3838
with:
3939
args: --shepherd
4040

@@ -57,7 +57,7 @@ jobs:
5757
steps:
5858
- uses: actions/checkout@v4
5959
- name: Cache Composer dependencies
60-
uses: actions/cache@v3
60+
uses: actions/cache@v4
6161
with:
6262
path: /tmp/composer-cache
6363
key: ${{ runner.os }}-${{ hashFiles('**/composer.lock') }}

.phive/phars.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<phive xmlns="https://phar.io/phive">
3-
<phar name="phpunit" version="^10.0.0" installed="10.5.3" location="./tools/phpunit" copy="true"/>
4-
<phar name="psalm" version="^5.12.0" installed="5.17.0" location="./tools/psalm" copy="true"/>
3+
<phar name="phpunit" version="^10.0.0" installed="10.5.45" location="./tools/phpunit" copy="true"/>
4+
<phar name="psalm" version="~6.4.0" installed="6.4.1" location="./tools/psalm" copy="true"/>
55
<phar name="phpcpd" version="^6.0.0" installed="6.0.3" location="./tools/phpcpd" copy="true"/>
66
</phive>

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ There are pretty much no dependencies with some exceptions:
3333

3434
- If you want to use the `toJSONFile()` method, you need to install `ext-json` (PHP's PECL JSON extension) as well.
3535
- If you want to use the igbinary serializer, `ext-igbinary` is required. See [php-ext-igbinary](https://github.com/igbinary/igbinary).
36+
- If you want to use the msgpack serializer, `ext-msgpack` is required. See [php-ext-msgpack](https://github.com/msgpack/msgpack-php).
3637
- If you want to use LZ4 compression, `ext-lz4` is required. See [php-ext-lz4](https://github.com/kjdev/php-ext-lz4).
3738

3839
## Usage
@@ -62,9 +63,9 @@ The constructor of `LargeArrayBuffer` provides some options:
6263

6364
1. You can set the threshold when to move the data to disk. When pushing data to the buffer, it is stored in memory until it gets too large.
6465
E.g.: `new LargeArrayBuffer(512);` to set a 512 MiB threshold.
65-
1. You can choose either the PHP serializer or the [igbinary](https://github.com/igbinary/igbinary) serializer (PHP serializer is default).
66+
1. You can choose either the PHP serializer, the [igbinary](https://github.com/igbinary/igbinary) serializer or the [msgpack](https://github.com/msgpack/msgpack-php) serializer (PHP serializer is default).
6667
E.g.: `new LargeArrayBuffer(serializer: LargeArrayBuffer::COMPRESSION_IGBINARY);`
67-
1. You can enable GZIP or LZ4 compression for the serialized items. Although this is recommended only if your items are pretty big like > 1 KiB each. E.g.: `new LargeArrayBuffer(compression: LargeArrayBuffer::COMPRESSION_GZIP);`. Note, that LZ4 compression requires [ext-lz4](https://github.com/kjdev/php-ext-lz4) to be installed.
68+
1. You can enable GZIP or LZ4 compression for the serialized items. Although this is recommended only if your items are pretty big like > 1 KiB each. E.g.: `new LargeArrayBuffer(compression: LargeArrayBuffer::COMPRESSION_GZIP);`. Note, that LZ4 compression requires [ext-lz4](https://github.com/kjdev/php-ext-lz4) to be loaded.
6869

6970
### Read from the buffer
7071

bench/benchmark.php

Lines changed: 80 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ function printResult(string $label, array $metrics, string $key, int $tabs = 1,
9797
unset($buf);
9898

9999
// buffer with LZ4
100-
if(function_exists('lz4_compress')){
100+
if(extension_loaded('lz4')){
101101
$start = microtime(true);
102102
$memBefore = memory_get_usage(true);
103103
$buf = new LargeArrayBuffer(128, compression: LargeArrayBuffer::COMPRESSION_LZ4);
@@ -118,7 +118,7 @@ function printResult(string $label, array $metrics, string $key, int $tabs = 1,
118118
unset($buf);
119119
}
120120

121-
if(function_exists('igbinary_serialize')){
121+
if(extension_loaded('igbinary')){
122122
// normal buffer with igbinary
123123
$start = microtime(true);
124124
$memBefore = memory_get_usage(true);
@@ -160,7 +160,7 @@ function printResult(string $label, array $metrics, string $key, int $tabs = 1,
160160
unset($buf);
161161

162162
// buffer with LZ4 and igbinary
163-
if(function_exists('lz4_compress')){
163+
if(extension_loaded('lz4')){
164164
$start = microtime(true);
165165
$memBefore = memory_get_usage(true);
166166
$buf = new LargeArrayBuffer(128, serializer: LargeArrayBuffer::SERIALIZER_IGBINARY, compression: LargeArrayBuffer::COMPRESSION_LZ4);
@@ -182,6 +182,70 @@ function printResult(string $label, array $metrics, string $key, int $tabs = 1,
182182
}
183183
}
184184

185+
if(extension_loaded('msgpack')){
186+
// normal buffer with msgpack
187+
$start = microtime(true);
188+
$memBefore = memory_get_usage(true);
189+
$buf = new LargeArrayBuffer(128, serializer: LargeArrayBuffer::SERIALIZER_MSGPACK);
190+
$bench->bufferMeasurementsFill($buf);
191+
$metrics['fill_buffer_mp'][] = [
192+
'time' => microtime(true) - $start,
193+
'mem' => memory_get_usage(true) - $memBefore,
194+
'size' => $buf->getSize()
195+
];
196+
197+
$start = microtime(true);
198+
$bench->bufferMeasurementsIterate($buf);
199+
$metrics['iterate_buffer_mp'][] = [
200+
'time' => microtime(true) - $start,
201+
'mem' => memory_get_usage(true) - $memBefore,
202+
'size' => $buf->getSize()
203+
];
204+
unset($buf);
205+
206+
// buffer with GZIP and msgpack
207+
$start = microtime(true);
208+
$memBefore = memory_get_usage(true);
209+
$buf = new LargeArrayBuffer(128, serializer: LargeArrayBuffer::SERIALIZER_MSGPACK, compression: LargeArrayBuffer::COMPRESSION_GZIP);
210+
$bench->bufferMeasurementsFill($buf);
211+
$metrics['fill_buffer_gz_mp'][] = [
212+
'time' => microtime(true) - $start,
213+
'mem' => memory_get_usage(true) - $memBefore,
214+
'size' => $buf->getSize()
215+
];
216+
217+
$start = microtime(true);
218+
$bench->bufferMeasurementsIterate($buf);
219+
$metrics['iterate_buffer_gz_mp'][] = [
220+
'time' => microtime(true) - $start,
221+
'mem' => memory_get_usage(true) - $memBefore,
222+
'size' => $buf->getSize()
223+
];
224+
unset($buf);
225+
226+
// buffer with LZ4 and msgpack
227+
if(extension_loaded('lz4')){
228+
$start = microtime(true);
229+
$memBefore = memory_get_usage(true);
230+
$buf = new LargeArrayBuffer(128, serializer: LargeArrayBuffer::SERIALIZER_MSGPACK, compression: LargeArrayBuffer::COMPRESSION_LZ4);
231+
$bench->bufferMeasurementsFill($buf);
232+
$metrics['fill_buffer_lz4_mp'][] = [
233+
'time' => microtime(true) - $start,
234+
'mem' => memory_get_usage(true) - $memBefore,
235+
'size' => $buf->getSize()
236+
];
237+
238+
$start = microtime(true);
239+
$bench->bufferMeasurementsIterate($buf);
240+
$metrics['iterate_buffer_lz4_mp'][] = [
241+
'time' => microtime(true) - $start,
242+
'mem' => memory_get_usage(true) - $memBefore,
243+
'size' => $buf->getSize()
244+
];
245+
unset($buf);
246+
}
247+
}
248+
185249
unset($bench);
186250
}
187251

@@ -191,17 +255,27 @@ function printResult(string $label, array $metrics, string $key, int $tabs = 1,
191255
printResult('Iterate over buffer', $metrics, 'iterate_buffer', 3, true);
192256
printResult('Fill buffer (GZIP)', $metrics, 'fill_buffer_gz', 3, true);
193257
printResult('Iterate over buffer (GZIP)', $metrics, 'iterate_buffer_gz', 2, true);
194-
if(function_exists('lz4_compress')){
258+
if(extension_loaded('lz4')){
195259
printResult('Fill buffer (LZ4)', $metrics, 'fill_buffer_lz4', 3, true);
196260
printResult('Iterate over buffer (LZ4)', $metrics, 'iterate_buffer_lz4', 2, true);
197261
}
198-
if(function_exists('igbinary_serialize')){
262+
if(extension_loaded('igbinary')){
199263
printResult('Fill buffer (igbinary)', $metrics, 'fill_buffer_ig', 2, true);
200264
printResult('Iterate over buffer (igbinary)', $metrics, 'iterate_buffer_ig', 1, true);
201265
printResult('Fill buffer (GZIP, igbinary)', $metrics, 'fill_buffer_gz_ig', 2, true);
202266
printResult('Iterate over buffer (GZIP, igbinary)', $metrics, 'iterate_buffer_gz_ig', 1, true);
203-
if(function_exists('lz4_compress')){
267+
if(extension_loaded('lz4')){
204268
printResult('Fill buffer (LZ4, igbinary)', $metrics, 'fill_buffer_lz4_ig', 2, true);
205269
printResult('Iterate over buffer (LZ4, igbinary)', $metrics, 'iterate_buffer_lz4_ig', 1, true);
206270
}
207271
}
272+
if(extension_loaded('msgpack')){
273+
printResult('Fill buffer (msgpack)', $metrics, 'fill_buffer_mp', 2, true);
274+
printResult('Iterate over buffer (msgpack)', $metrics, 'iterate_buffer_mp', 1, true);
275+
printResult('Fill buffer (GZIP, msgpack)', $metrics, 'fill_buffer_gz_mp', 2, true);
276+
printResult('Iterate over buffer (GZIP, msgpack)', $metrics, 'iterate_buffer_gz_mp', 1, true);
277+
if(extension_loaded('lz4')){
278+
printResult('Fill buffer (LZ4, msgpack)', $metrics, 'fill_buffer_lz4_mp', 2, true);
279+
printResult('Iterate over buffer (LZ4, msgpack)', $metrics, 'iterate_buffer_lz4_mp', 1, true);
280+
}
281+
}

composer.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "nerou/large-array-buffer",
3-
"version": "1.0.1",
3+
"version": "1.1.0",
44
"type": "library",
55
"license": "MIT",
66
"authors": [
@@ -14,8 +14,9 @@
1414
"suggest": {
1515
"ext-json": "Requirement of toJSONFile() method",
1616
"ext-zlib": "To enable support for GZIP compression",
17-
"ext-lz4": "To enable support for LZ4 compression",
18-
"ext-igbinary": "To enable support for igbinary serializer"
17+
"ext-lz4": "To enable support of LZ4 compression",
18+
"ext-igbinary": "To enable support for igbinary serializer",
19+
"ext-msgpack": "To enable support for msgpack serializer"
1920
},
2021
"require": {
2122
"php": ">=8.0"

psalm.baseline.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
<UndefinedFunction>
55
<code>lz4_compress($serialized)</code>
66
<code>lz4_uncompress($compressed)</code>
7+
<code>msgpack_serialize($item)</code>
8+
<code>msgpack_unserialize($this->current)</code>
79
</UndefinedFunction>
810
</file>
911
</files>

psalm.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
errorBaseline="psalm.baseline.xml"
88
errorLevel="2"
99
findUnusedBaselineEntry="false"
10-
findUnusedCode="false">
10+
findUnusedCode="false"
11+
phpVersion="8.0">
1112

1213
<projectFiles>
1314
<directory name="src" />

src/LargeArrayBuffer.php

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ class LargeArrayBuffer implements ArrayBufferInterface {
1212

1313
public const SERIALIZER_PHP = 1;
1414
public const SERIALIZER_IGBINARY = 2;
15+
public const SERIALIZER_MSGPACK = 3;
1516

1617
public const COMPRESSION_NONE = 0;
1718
public const COMPRESSION_GZIP = 1;
@@ -57,13 +58,16 @@ class LargeArrayBuffer implements ArrayBufferInterface {
5758
*/
5859
public function __construct(int $maxMemoryMiB = 1024, int $serializer = self::SERIALIZER_PHP, int $compression = self::COMPRESSION_NONE) {
5960
$this->serializer = $serializer;
60-
if($this->serializer === self::SERIALIZER_IGBINARY && !function_exists('igbinary_serialize')){
61-
throw new \InvalidArgumentException('igbinary serializer was requested, but ext-igbinary is not installed');
61+
if($this->serializer === self::SERIALIZER_IGBINARY && !extension_loaded('igbinary')){
62+
throw new \InvalidArgumentException('igbinary serializer was requested, but ext-igbinary is not loaded');
63+
}
64+
if($this->serializer === self::SERIALIZER_MSGPACK && !extension_loaded('msgpack')){
65+
throw new \InvalidArgumentException('msgpack serializer was requested, but ext-msgpack is not loaded');
6266
}
6367

6468
$this->compression = $compression;
65-
if($this->compression === self::COMPRESSION_LZ4 && !function_exists('lz4_compress')){
66-
throw new \InvalidArgumentException('LZ4 compression was requested, but ext-lz4 is not installed');
69+
if($this->compression === self::COMPRESSION_LZ4 && !extension_loaded('lz4')){
70+
throw new \InvalidArgumentException('LZ4 compression was requested, but ext-lz4 is not loaded');
6771
}
6872

6973
$stream = fopen('php://temp/maxmemory:'.($maxMemoryMiB * 1024 * 1024), 'r+');
@@ -75,13 +79,17 @@ public function __construct(int $maxMemoryMiB = 1024, int $serializer = self::SE
7579

7680
/**
7781
* @psalm-param E $item
78-
* @throws \RuntimeException if unable to write to php://temp
82+
* @throws \RuntimeException if unable to write to php://temp, the serialization failed or the compression failed
7983
*/
8084
public function push(mixed $item): void {
8185
$serialized = match($this->serializer){
8286
self::SERIALIZER_IGBINARY => igbinary_serialize($item),
87+
self::SERIALIZER_MSGPACK => msgpack_serialize($item),
8388
default => serialize($item)
8489
};
90+
if($serialized === false){
91+
throw new \RuntimeException('failed to serialize data');
92+
}
8593
/** @var string|false $compressed */
8694
$compressed = match($this->compression){
8795
self::COMPRESSION_GZIP => gzdeflate($serialized),
@@ -148,6 +156,7 @@ public function current(): mixed {
148156
/** @psalm-var E $res */
149157
$res = match($this->serializer){
150158
self::SERIALIZER_IGBINARY => igbinary_unserialize($this->current),
159+
self::SERIALIZER_MSGPACK => msgpack_unserialize($this->current),
151160
default => unserialize($this->current)
152161
};
153162
return $res;
@@ -213,7 +222,14 @@ public function toJSONFile($dest, int $flags = JSON_THROW_ON_ERROR, int $depth =
213222
if(($flags & JSON_PRETTY_PRINT) > 0){
214223
fwrite($stream, PHP_EOL.' ');
215224
}
216-
fwrite($stream, json_encode($item, $flags, $depth));
225+
$json = json_encode($item, $flags, $depth);
226+
if($json === false){
227+
if(is_string($dest)){
228+
fclose($stream);
229+
}
230+
throw new \RuntimeException('failed to serialize data');
231+
}
232+
fwrite($stream, $json);
217233
fflush($stream);
218234
$first = false;
219235
}

0 commit comments

Comments
 (0)