-
Notifications
You must be signed in to change notification settings - Fork 636
fix(hstore): don't push sysprop-only range queries down to the store #3184
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
base: master
Are you sure you want to change the base?
Changes from all commits
847fab9
1072872
0ecc10a
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 |
|---|---|---|
|
|
@@ -568,8 +568,13 @@ private ConditionQuery prepareConditionQuery(ConditionQuery conditionQuery) { | |
| } | ||
| } | ||
| if (newConditions.size() > 0) { | ||
| conditionQuery.resetConditions(newConditions); | ||
| return conditionQuery; | ||
| // NOTE: copy before reset, the origin query is still used by core | ||
| // for result filtering after the backend scan returns; drop the | ||
| // back reference so the serialized payload stays flat | ||
| ConditionQuery pushdown = conditionQuery.copy(); | ||
| pushdown.resetConditions(newConditions); | ||
| pushdown.setOriginQuery(null); | ||
| return pushdown; | ||
| } else { | ||
| return null; | ||
| } | ||
|
|
@@ -594,8 +599,11 @@ private ConditionQuery prepareConditionQueryList(ConditionQuery conditionQuery) | |
| } | ||
| } | ||
| if (newConditions.size() > 0) { | ||
| conditionQuery.resetConditions(newConditions); | ||
| return conditionQuery; | ||
| // NOTE: copy before reset, see prepareConditionQuery() | ||
| ConditionQuery pushdown = conditionQuery.copy(); | ||
|
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 guard is pre-existing and outside this diff, so not a change request on this PR: worth a follow-up on #3090, or a line in the new comment saying why the list path is different. Confidence: the guard mismatch is confirmed by reading the two methods. Whether this batch path actually hits the decode failure is not, since I could not reproduce it locally.
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. Agreed, and thanks for confirming the guard mismatch. Leaving the list path untouched here to keep the diff minimal — will flag |
||
| pushdown.resetConditions(newConditions); | ||
| pushdown.setOriginQuery(null); | ||
|
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 copy-not-mutate change lands in both prepare methods, but the new tests cover only Requested change: make
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. Done in 0ecc10a — |
||
| return pushdown; | ||
| } else { | ||
| return null; | ||
| } | ||
|
|
@@ -623,7 +631,6 @@ protected BackendColumnIterator queryByRange(Session session, | |
| type |= query.inclusiveEnd() ? | ||
| Session.SCAN_LTE_END : Session.SCAN_LT_END; | ||
| } | ||
| ConditionQuery cq; | ||
| Query origin = query.originQuery(); | ||
| byte[] position = null; | ||
| byte[] ownerStart = this.ownerByQueryDelegate.apply(query.resultType(), | ||
|
|
@@ -640,21 +647,20 @@ protected BackendColumnIterator queryByRange(Session session, | |
| if (query.paging() && !query.page().isEmpty()) { | ||
| position = PageState.fromString(query.page()).position(); | ||
| } | ||
| byte[] queryBytes = null; | ||
| if (origin instanceof ConditionQuery && | ||
| (query.resultType().isEdge() || query.resultType().isVertex())) { | ||
| cq = (ConditionQuery) query.originQuery(); | ||
|
|
||
| // LOG.debug("query {} with ownerKeyFrom: {}, ownerKeyTo: {}, " + | ||
| // "keyFrom: {}, keyTo: {}, " + | ||
| // "scanType: {}, conditionQuery: {}", | ||
| // this.table(), bytes2String(ownerStart), | ||
| // bytes2String(ownerEnd), bytes2String(start), | ||
| // bytes2String(end), type, cq.bytes()); | ||
| return session.scan(this.table(), ownerStart, | ||
| ownerEnd, start, end, type, cq.bytes(), position); | ||
| } | ||
| return session.scan(this.table(), ownerStart, | ||
| ownerEnd, start, end, type, null, position); | ||
| // Same guard as queryByPrefix(): only push the query down to the | ||
| // store when user-prop conditions remain. A sort-key prefix/range | ||
| // query keeps sysprop conditions only (owner vertex, direction, | ||
| // label, sort values), which are already enforced by the key | ||
| // range, and the store-side row decoder cannot parse the raw | ||
| // property layout written by the server (see issue #3090). | ||
| ConditionQuery cq = prepareConditionQuery((ConditionQuery) origin); | ||
| queryBytes = cq == null ? null : cq.bytes(); | ||
| } | ||
| return session.scan(this.table(), ownerStart, ownerEnd, start, end, | ||
| type, queryBytes, position); | ||
| } | ||
|
|
||
| static boolean shouldUseOrderedRangeScan(IdRangeQuery query) { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 The copy keeps a link back to the query it came from, so the payload grows by one nesting level.
ConditionQuery.copy()ends withquery.originQuery(this)(hugegraph-corebackend/query/ConditionQuery.java:577),Query.originQueryis non-transient (backend/query/Query.java:78), andbytes()serializes with aGsonthat registers type adapters but no exclusion strategy (ConditionQuery.java:81-85, 980-983).Measured on a build of this head, for an edge query with owner vertex, direction, label and one user-prop condition, using the shape the pipeline produces (the origin is itself a copy from
GraphTransaction.java:1591, so one level of nesting predates this PR):No behaviour change: store-side consumers read only the top-level query (
hg-store-core/.../business/FilterIterator.java:53-85,hg-store-node/.../query/stages/FilterStage.java:36-52) and nothing inhugegraph-storereadsoriginQuery.Requested change:
pushdown.setOriginQuery(null);after the reset, in both this method andprepareConditionQueryList().Query.setOriginQuery(Query)is public (backend/query/Query.java:142-144), and the pushdown is discarded right afterbytes(), so nothing else observes the link.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in 1072872 —
setOriginQuery(null)on the pushdown copy in both prepare methods. Thanks for measuring the payload; the nesting predating this PR (origin already being a copy fromGraphTransaction.java:1591) was a good catch I had missed entirely.