-
Notifications
You must be signed in to change notification settings - Fork 59
perf: reduce database document and conversion allocations #958
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -45,17 +45,21 @@ public function __construct(array $input = []) | |
| continue; | ||
| } | ||
|
|
||
| $converted = false; | ||
| foreach ($value as $childKey => $child) { | ||
| // An array value is either a list of nested sub-documents or a list of | ||
| // plain items (dates, numbers, strings): wrap the former, leave the latter. | ||
| // is_array() tells them apart and avoids array-accessing a non-array | ||
| // value (e.g. a UTCDateTime), which would otherwise fatal. | ||
| if (\is_array($child) && (isset($child['$id']) || isset($child['$collection']))) { | ||
| $value[$childKey] = new self($child); | ||
| $converted = true; | ||
| } | ||
| } | ||
|
|
||
| $input[$key] = $value; | ||
| if ($converted) { | ||
| $input[$key] = $value; | ||
| } | ||
| } | ||
|
|
||
| parent::__construct($input); | ||
|
|
@@ -430,7 +434,7 @@ public function getArrayCopy(array $allow = [], array $disallow = []): array | |
|
|
||
| $output = []; | ||
|
|
||
| foreach ($array as $key => &$value) { | ||
| foreach ($array as $key => $value) { | ||
| if (!empty($allow) && !\in_array($key, $allow)) { // Export only allow fields | ||
| continue; | ||
| } | ||
|
|
@@ -442,17 +446,12 @@ public function getArrayCopy(array $allow = [], array $disallow = []): array | |
| if ($value instanceof self) { | ||
| $output[$key] = $value->getArrayCopy($allow, $disallow); | ||
| } elseif (\is_array($value)) { | ||
| foreach ($value as $childKey => &$child) { | ||
| if ($child instanceof self) { | ||
| $output[$key][$childKey] = $child->getArrayCopy($allow, $disallow); | ||
| } else { | ||
| $output[$key][$childKey] = $child; | ||
| } | ||
| } | ||
| $value = \array_map( | ||
| fn ($item) => $item instanceof self ? $item->getArrayCopy($allow, $disallow) : $item, | ||
| $value | ||
| ); | ||
|
|
||
|
Comment on lines
+449
to
453
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The unconditional Knowledge Base Used: Document lifecycle and representation Prompt To Fix With AIThis is a comment left during a code review.
Path: src/Database/Document.php
Line: 449-453
Comment:
**Scalar Arrays Are Rebuilt**
The unconditional `array_map()` rebuilds every exported array, even when it contains only scalar values. The same pattern in `__clone()` also copies scalar-only arrays instead of retaining their copy-on-write storage. For large fields, this reintroduces allocation overhead that the PR is intended to avoid. The revised test raises the allocation allowance and removes clone allocation coverage rather than preserving the earlier optimization.
**Knowledge Base Used:** [Document lifecycle and representation](https://app.greptile.com/appwrite/-/custom-context/knowledge-base/utopia-php/database/-/docs/document-lifecycle.md)
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a deliberate tradeoff: we measured the conditional ReflectionReference approach and chose the simpler implementation without reflection. Scalar arrays still get copied on export, but removing reference iteration avoids allocating a PHP reference wrapper for every element. In the 2,000-operation scalar-array export benchmark, requested allocation bytes fell from 112,928,000 on the base implementation to 41,040,000 with this version. The reflection-based version allocated less, but we are accepting that difference for simplicity. Cloning retains the base branch's implementation; this PR no longer claims a clone allocation improvement. The revised export test checks the optimization we are shipping (avoiding reference-allocation overhead), rather than requiring copy-on-write sharing that we deliberately removed. It fails on the base implementation and passes here. Behavior tests retain explicit-reference detachment and nested-document isolation coverage. The PR description now explains this scope and the measurements: the complete PR reduces allocation events by 25.83% and requested Zend bytes by 17.28% on the local API workload. We will keep the simpler version and are not restoring ReflectionReference for this PR. |
||
| if (empty($value)) { | ||
| $output[$key] = $value; | ||
| } | ||
| $output[$key] = $value; | ||
| } else { | ||
| $output[$key] = $value; | ||
| } | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.