Skip to content

configurable apcu compression level#96

Merged
kjdev merged 1 commit into
kjdev:masterfrom
pavetheway91:apcu_level
Jun 3, 2026
Merged

configurable apcu compression level#96
kjdev merged 1 commit into
kjdev:masterfrom
pavetheway91:apcu_level

Conversation

@pavetheway91
Copy link
Copy Markdown
Contributor

@pavetheway91 pavetheway91 commented May 28, 2026

New ini setting "zstd.apcu_compression_level"

Summary by CodeRabbit

  • New Features

    • New INI setting zstd.apcu_compression_level (when APCu support is enabled) to control APCu zstd compression level at runtime. Configured levels are validated; invalid or zero values fall back to the safe default.
    • Module initialization and INI registration/display are now consistent across PHP versions.
  • Tests

    • APCu serializer test updated to compare stored entry sizes across compression levels and assert when higher compression yields smaller entries.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 28, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0efd9c05-4873-480e-b399-5b91b7a9570c

📥 Commits

Reviewing files that changed from the base of the PR and between ab1ae58 and 02f264a.

📒 Files selected for processing (3)
  • php_zstd.h
  • tests/apcu_serializer.phpt
  • zstd.c
🚧 Files skipped from review as they are similar to previous changes (2)
  • tests/apcu_serializer.phpt
  • zstd.c

📝 Walkthrough

Walkthrough

Adds a guarded module global and INI for APCu compression level; APCu serializer reads and validates the configured level (falls back to default) and uses it for compression; module/global wiring and tests updated to exercise different levels.

Changes

APCu Compression Level Configuration

Layer / File(s) Summary
Module global field declaration and guard adjustment
php_zstd.h
Unconditionally declares ZEND_BEGIN_MODULE_GLOBALS(zstd) and adds zend_long apcu_compression_level under #if defined(HAVE_APCU_SUPPORT); adjusts surrounding preprocessor guard placement.
APCu serializer reads and validates level
zstd.c
Reads PHP_ZSTD_G(apcu_compression_level), validates via zstd_check_compress_level (treating 0 as invalid), falls back to ZSTD_CLEVEL_DEFAULT if invalid, and uses the chosen level in ZSTD_compress.
INI registration and lifecycle wiring
zstd.c
Adds zstd.apcu_compression_level INI entry (guarded by HAVE_APCU_SUPPORT) wired to the module global; adjusts REGISTER/UNREGISTER/DISPLAY INI calls to run without the previous PHP_VERSION_ID >= 80000 guard where applicable.
Module entry & GINIT adjustments
zstd.c
ZEND_GINIT_FUNCTION(zstd) is defined unconditionally with per-version assignments inside; zend_module_entry now unconditionally uses PHP_MODULE_GLOBALS(zstd), PHP_GINIT(zstd), and STANDARD_MODULE_PROPERTIES_EX.
APCu serializer test for large payloads
tests/apcu_serializer.phpt
Adds getEntrySize() helper, stores a payload at compression levels 3 and 19, compares APCu mem_size for the key, and prints SMALLER when level 19 yields a smaller stored entry; expected output updated.

Sequence Diagram(s)

sequenceDiagram
  participant Test as tests/apcu_serializer.phpt
  participant APCuSerializer as APCu_zstd_serializer
  participant ModuleGlobals as PHP_ZSTD_G(apcu_compression_level)
  participant ZSTD as ZSTD_compress

  Test->>APCuSerializer: apcu_store(big_payload)
  APCuSerializer->>ModuleGlobals: read apcu_compression_level
  APCuSerializer->>APCuSerializer: validate level (zstd_check_compress_level), fallback if invalid/0
  APCuSerializer->>ZSTD: ZSTD_compress(data, chosen_level)
  ZSTD-->>APCuSerializer: compressed_data
  APCuSerializer-->>Test: store result and update apcu_cache_info
Loading

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 I hop through bytes and tweak the tune,
I sniff the INI under the moon,
I set the level, compress with care,
I check the cache and tally the share,
"SMALLER!" I sing — victory in the lair.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title 'configurable apcu compression level' directly and concisely summarizes the main change: adding a configurable INI setting for APCu compression level.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 Infer (1.2.0)
zstd.c

zstd.c:28:10: fatal error: 'php.h' file not found
28 | #include <php.h>
| ^~~~~~~
1 error generated.
Error: the following clang command did not run successfully:
/opt/infer-linux-x86_64-v1.2.0/lib/infer/facebook-clang-plugins/clang/install/bin/clang-18
@/tmp/coderabbit-infer/02f264af0d47be87e07e0d648b81a0bd0811bdb5-2f57b45144c7d836/tmp/clang_command_.tmp.afd53f.txt
++Contents of '/tmp/coderabbit-infer/02f264af0d47be87e07e0d648b81a0bd0811bdb5-2f57b45144c7d836/tmp/clang_command_.tmp.afd53f.txt':
"-cc1" "-load"
"/opt/infer-linux-x86_64-v1.2.0/lib/infer/infer/bin/../../facebook-clang-plugins/libtooling/build/FacebookClangPlugin.dylib"
"-add-plugin" "BiniouASTExporter" "-plugin-arg-BiniouASTExporter" "-"
"-plugin-arg-BiniouASTExporter" "PREPEND_CURRENT_DIR=1"
"-plugin-arg-BiniouASTExporter" "MAX_STRING_SIZE=65535" "-cc1" "-triple"
"x86_64-unknown-linux-gnu" "-emit-obj" "-mrelax-all" "-disable-free"
"-clear-ast-before-backend" "-disable

... [truncated 635 characters] ...

ystem"
"/opt/infer-linux-x86_64-v1.2.0/lib/infer/facebook-clang-plugins/clang/install/lib/clang/18/include"
"-internal-isystem" "/usr/local/include" "-internal-isystem"
"/usr/lib/gcc/x86_64-linux-gnu/12/../../../../x86_64-linux-gnu/include"
"-internal-externc-isystem" "/usr/include/x86_64-linux-gnu"
"-internal-externc-isystem" "/include" "-internal-externc-isystem"
"/usr/include" "-Wno-ignored-optimization-argument" "-Wno-everything"
"-ferror-limit" "19" "-fgnuc-version=4.2.1" "-fskip-odr-check-in-gmf"
"-D__GCC_HAVE_DWARF2_CFI_ASM=1" "-o"
"/tmp/coderabbit-infer/2f57b45144c7d836/file.o" "-x" "c" "zstd.c" "-O0"
"-fno-builtin" "-include"
"/opt/infer-linux-x86_64-v1.2.0/lib/infer/infer/bin/../lib/clang_wrappers/global_defines.h"
"-Wno-everything"


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@kjdev
Copy link
Copy Markdown
Owner

kjdev commented May 29, 2026

I think the implementation is good, but I'd also like to see some test code. 

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/apcu_serializer.phpt`:
- Around line 72-79: The test reads mem_size from
apcu_cache_info()['cache_list'][0] and asserts $b < $a which is flaky; instead,
find the mem_size entry for the stored key "big_entry" from apcu_cache_info()
(search cache_list entries for ['info'] or ['key'] == 'big_entry') and compare
that mem_size before and after setting ini_set('zstd.apcu_compression_level',
19) so you measure the specific item's size, and change the assertion to allow
equality (use $b <= $a) to avoid nondeterministic failures; apply the same fix
to the second occurrence around the later assertion.
- Around line 67-68: Replace the raw file_get_contents(...) expression with a
guarded read: call file_get_contents(...) into a variable (e.g. $payload or
$zstd_source), check if the result === false, and if so print an explicit
failure message to STDERR and exit with non‑zero status (e.g. fwrite(STDERR,
"Failed to read fixture: ...\n"); exit(1);); then use that variable where the
original file_get_contents(...) result was used in the test.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d988a944-b5df-4c11-84c7-9d38c5431e55

📥 Commits

Reviewing files that changed from the base of the PR and between bfe2a02 and d2741d8.

📒 Files selected for processing (3)
  • php_zstd.h
  • tests/apcu_serializer.phpt
  • zstd.c
✅ Files skipped from review due to trivial changes (1)
  • php_zstd.h
🚧 Files skipped from review as they are similar to previous changes (1)
  • zstd.c

Comment thread tests/apcu_serializer.phpt Outdated
Comment thread tests/apcu_serializer.phpt Outdated
@pavetheway91 pavetheway91 force-pushed the apcu_level branch 2 times, most recently from 5b02610 to 3f1e32d Compare May 29, 2026 04:20
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/apcu_serializer.phpt`:
- Around line 66-71: The test iterates apcu_cache_info()['cache_list'] without
guarding that apcu_cache_info() returned valid metadata, which can raise
warnings and break the test; update the code around the foreach (the call to
apcu_cache_info() and the loop over 'cache_list') to first fetch the result into
a variable, verify it's not false/null and that 'cache_list' exists and is an
array, and if not return null explicitly before attempting to iterate.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 05daba65-f658-41a1-b8af-dd9f5f45e23e

📥 Commits

Reviewing files that changed from the base of the PR and between 5b02610 and 3f1e32d.

📒 Files selected for processing (3)
  • php_zstd.h
  • tests/apcu_serializer.phpt
  • zstd.c
🚧 Files skipped from review as they are similar to previous changes (2)
  • php_zstd.h
  • zstd.c

Comment thread tests/apcu_serializer.phpt Outdated
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 29, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 30, 2026

✅ Actions performed

Reviews resumed.

@pavetheway91
Copy link
Copy Markdown
Contributor Author

pavetheway91 commented May 30, 2026

fixed php7

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
tests/apcu_serializer.phpt (1)

87-89: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Make the size assertion non-flaky on Line 87.

Using strict $b < $a can fail nondeterministically when both levels produce equal APCu entry size. Use <= to keep the intent while stabilizing CI.

Suggested patch
-if ($a !== null && $b !== null && $b < $a) {
+if ($a !== null && $b !== null && $b <= $a) {
   echo "SMALLER\n";
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/apcu_serializer.phpt` around lines 87 - 89, The size comparison using
strict inequality currently reads as a potential flaky check (the condition
using $b < $a), so update the conditional in the test to use a non-strict
comparison ($b <= $a) when evaluating $a and $b to stabilize the assertion that
the second size is not greater than the first while leaving the echo "SMALLER\n"
behavior intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@php_zstd.h`:
- Around line 47-60: The zend_zstd_globals struct can be empty when
HAVE_APCU_SUPPORT is unset and PHP_VERSION_ID < 80000; ensure the globals struct
always has at least one member by adding a fallback dummy field (e.g., zend_long
dummy or char dummy) inside the ZEND_BEGIN_MODULE_GLOBALS(zstd) block under the
appropriate `#else` branch so zend_zstd_globals is never empty while keeping
ZEND_BEGIN_MODULE_GLOBALS(zstd) and ZEND_DECLARE_MODULE_GLOBALS(zstd) unguarded;
update any conditional compilation around the other members
(output_compression*, ob_handler, handler_registered, compression_coding,
apcu_compression_level) to retain their current guards.

---

Duplicate comments:
In `@tests/apcu_serializer.phpt`:
- Around line 87-89: The size comparison using strict inequality currently reads
as a potential flaky check (the condition using $b < $a), so update the
conditional in the test to use a non-strict comparison ($b <= $a) when
evaluating $a and $b to stabilize the assertion that the second size is not
greater than the first while leaving the echo "SMALLER\n" behavior intact.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d626bf45-0ef0-44b8-88e6-f063b3ea1ca6

📥 Commits

Reviewing files that changed from the base of the PR and between 3f1e32d and 6e79e81.

📒 Files selected for processing (3)
  • php_zstd.h
  • tests/apcu_serializer.phpt
  • zstd.c
🚧 Files skipped from review as they are similar to previous changes (1)
  • zstd.c

Comment thread php_zstd.h
Comment thread php_zstd.h Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
php_zstd.h (1)

60-60: ⚡ Quick win

Clarify the comment per maintainer feedback.

The maintainer previously suggested using a clearer comment like "dummy to avoid empty structures" to better convey the intent of this field.

📝 Suggested comment improvement
-    int unused_dummy; /* no empty struct */
+    int unused_dummy; /* dummy to avoid empty structures */
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@php_zstd.h` at line 60, Update the comment for the struct field unused_dummy
to clearly state its purpose: replace the vague "no empty struct" with a concise
explanatory comment such as "dummy to avoid empty structures" so readers
understand this field exists solely to prevent an empty struct; locate the field
named unused_dummy in php_zstd.h and change only the comment text accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@php_zstd.h`:
- Line 60: Update the comment for the struct field unused_dummy to clearly state
its purpose: replace the vague "no empty struct" with a concise explanatory
comment such as "dummy to avoid empty structures" so readers understand this
field exists solely to prevent an empty struct; locate the field named
unused_dummy in php_zstd.h and change only the comment text accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ec40df9a-994c-49cc-aa78-b8c5eb1aaf77

📥 Commits

Reviewing files that changed from the base of the PR and between 6e79e81 and ab1ae58.

📒 Files selected for processing (3)
  • php_zstd.h
  • tests/apcu_serializer.phpt
  • zstd.c
🚧 Files skipped from review as they are similar to previous changes (2)
  • tests/apcu_serializer.phpt
  • zstd.c

@kjdev
Copy link
Copy Markdown
Owner

kjdev commented Jun 1, 2026

Although this has not been verified in CI, when using ZTS with PHP 8.0 or earlier and APCu enabled, the apcu_compression_level global variable may not be assigned a ts_allocate_id, potentially leading to undefined behavior (crashes or incorrect reads) due to access to an uninitialized variable.

#if PHP_VERSION_ID >= 80000
ZEND_GINIT_FUNCTION(zstd)
{
#if defined(COMPILE_DL_ZSTD) && defined(ZTS)
    ZEND_TSRMLS_CACHE_UPDATE();
#endif

@pavetheway91
Copy link
Copy Markdown
Contributor Author

pavetheway91 commented Jun 1, 2026

Would this fix it?

ZEND_GINIT_FUNCTION(zstd)
{
#if defined(COMPILE_DL_ZSTD) && defined(ZTS)
    ZEND_TSRMLS_CACHE_UPDATE();
#endif
#if PHP_VERSION_ID >= 80000
    zstd_globals->ob_handler = NULL;
    zstd_globals->handler_registered = 0;
#endif
}

@kjdev
Copy link
Copy Markdown
Owner

kjdev commented Jun 2, 2026

We also need to check the following

zend_module_entry zstd_module_entry = {
#if defined(HAVE_APCU_SUPPORT)
    STANDARD_MODULE_HEADER_EX,
    NULL,
    zstd_module_deps,
#else
    STANDARD_MODULE_HEADER,
#endif
    "zstd",
    zstd_functions,
    ZEND_MINIT(zstd),
    ZEND_MSHUTDOWN(zstd),
    ZEND_RINIT(zstd),
    ZEND_RSHUTDOWN(zstd),
    ZEND_MINFO(zstd),
    PHP_ZSTD_VERSION,
#if PHP_VERSION_ID >= 80000
    PHP_MODULE_GLOBALS(zstd),
    PHP_GINIT(zstd),
    NULL,
    NULL,
    STANDARD_MODULE_PROPERTIES_EX
#else
    STANDARD_MODULE_PROPERTIES
#endif
};

@pavetheway91
Copy link
Copy Markdown
Contributor Author

Sure, I'll do several ZTS builds of PHP 7 and 8 and test with those too.

@pavetheway91
Copy link
Copy Markdown
Contributor Author

Yep, this coredumps at least with 7.4-zts.

I believe, I've got a fix for it already, but I'll do some additional tests first.

@pavetheway91
Copy link
Copy Markdown
Contributor Author

pavetheway91 commented Jun 2, 2026

ran some additional tests with:

php74
php74-zts
php80
php80-zts
php84

@kjdev kjdev merged commit 0c7644b into kjdev:master Jun 3, 2026
174 of 203 checks passed
@kjdev
Copy link
Copy Markdown
Owner

kjdev commented Jun 3, 2026

Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants