-
Notifications
You must be signed in to change notification settings - Fork 427
OAK-12352: Include diff indexes in the index definition status printer #3078
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: trunk
Are you sure you want to change the base?
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 |
|---|---|---|
|
|
@@ -23,10 +23,15 @@ | |
|
|
||
| import org.apache.felix.inventory.Format; | ||
| import org.apache.felix.inventory.InventoryPrinter; | ||
| import org.apache.jackrabbit.oak.api.PropertyState; | ||
| import org.apache.jackrabbit.oak.commons.json.JsonObject; | ||
| import org.apache.jackrabbit.oak.commons.json.JsopBuilder; | ||
| import org.apache.jackrabbit.oak.json.Base64BlobSerializer; | ||
| import org.apache.jackrabbit.oak.json.JsonSerializer; | ||
| import org.apache.jackrabbit.oak.plugins.index.IndexPathService; | ||
| import org.apache.jackrabbit.oak.plugins.index.diff.DiffIndex; | ||
| import org.apache.jackrabbit.oak.plugins.index.diff.DiffIndexMerger; | ||
| import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry; | ||
| import org.apache.jackrabbit.oak.spi.state.NodeState; | ||
| import org.apache.jackrabbit.oak.spi.state.NodeStateUtils; | ||
| import org.apache.jackrabbit.oak.spi.state.NodeStore; | ||
|
|
@@ -69,6 +74,17 @@ public void print(PrintWriter printWriter, Format format, boolean isZip) { | |
| NodeState idxState = NodeStateUtils.getNode(root, indexPath); | ||
| createSerializer(json).serialize(idxState); | ||
| } | ||
| // The "diff" indexes (diff.index / diff.index.optimizer) are not oak:QueryIndexDefinition nodes, so they | ||
| // are not returned by the IndexPathService and would otherwise be missing from the output. Add them | ||
| // explicitly, rendering their diff.json payload as inline JSON so the pending diff is readable. | ||
| for (String name : new String[] {DiffIndexMerger.DIFF_INDEX, DiffIndexMerger.DIFF_INDEX_OPTIMIZER}) { | ||
|
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. IMHO, there is a lot of logic for something that should be a printer
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. When I see this kind of "work around", it very often means there is a design flaw somewhere. It's likely not the issue of this PR, but something else (the complexity of this PR is a symptom). Before Before, printing was a natural walk through the tree outputting what ever was on it's path. Maybe we can make this "printing" a bit cleaner by splitting this method up: Move the logic to determine which diffIndexPaths to the indexPathService (where we add a method .getDiffPaths()) |
||
| String diffPath = "/oak:index/" + name; | ||
| NodeState idxState = NodeStateUtils.getNode(root, diffPath); | ||
| if (idxState.exists()) { | ||
| json.key(diffPath); | ||
| serializeDiffIndex(json, idxState); | ||
| } | ||
| } | ||
| json.endObject(); | ||
| printWriter.print(JsopBuilder.prettyPrint(json.toString())); | ||
| } | ||
|
|
@@ -81,4 +97,44 @@ public void setFilter(String filter) { | |
| private JsonSerializer createSerializer(JsopBuilder json) { | ||
| return new JsonSerializer(json, filter, new Base64BlobSerializer()); | ||
| } | ||
|
|
||
| /** | ||
| * Serialize a diff index node, inlining its {@code diff.json} payload as JSON. All other file child nodes are | ||
| * rendered as base64 blobs, for backward compatibility. | ||
| */ | ||
| private void serializeDiffIndex(JsopBuilder json, NodeState idxState) { | ||
| json.object(); | ||
|
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. I don't like so much that we have walking logic in this class and them more walking logic in the serializer class. The role of this class is to delegate to JsonSerializer (which consists in walking a NodeState and outputting in JSON what it finds). So it does the walking... we shouldn't be doing it here. Why are we doing it here ? Because we want a special processing of a certain parts : the inlining of the diff.json file object. Why don't we just update the serializer (eventually with a config) to add inlining of certain nodes and the configure the serializer with that option here ? Here we would not need the 2 extra loops as this would be taken care of by the serializer. |
||
| JsonSerializer serializer = createSerializer(json); | ||
| // definition properties (mirror the default filter, which drops :childOrder) | ||
| for (PropertyState p : idxState.getProperties()) { | ||
| if (":childOrder".equals(p.getName())) { | ||
| continue; | ||
| } | ||
| json.key(p.getName()); | ||
| serializer.serialize(p); | ||
| } | ||
| // non-hidden child nodes other than diff.json, rendered normally | ||
| for (ChildNodeEntry child : idxState.getChildNodeEntries()) { | ||
|
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. Is this running with the right order of child nodes? Or does it even matter here? (I struggle a bit to understand where OAK requires correct node ordering and where not) |
||
| String childName = child.getName(); | ||
| if (childName.startsWith(":") || "diff.json".equals(childName)) { | ||
| continue; | ||
| } | ||
| json.key(childName); | ||
| createSerializer(json).serialize(child.getNodeState()); | ||
|
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. Is the serializer so stateful that we need to recreate it ? |
||
| } | ||
| // diff.json: inline the JSON payload instead of a base64 blob | ||
| NodeState content = idxState.getChildNode("diff.json").getChildNode("jcr:content"); | ||
| String diff = content.exists() ? DiffIndex.tryReadString(content.getProperty("jcr:data")) : null; | ||
| if (diff != null) { | ||
| json.key("diff.json"); | ||
| try { | ||
| // Parse and re-serialize so a malformed diff.json cannot corrupt the whole output. | ||
| JsonObject.fromJson(diff, true).toJson(json); | ||
| } catch (Exception e) { | ||
| // Not valid JSON - keep the endpoint well-formed by emitting the raw payload as a string. | ||
| json.value(diff); | ||
| } | ||
| } | ||
| json.endObject(); | ||
| } | ||
| } | ||
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.
Detail (what confused Claude): In oak-doc/src/site/markdown/query/indexing.md we write:
The diff index consists of:
This contradicts the jcr:primaryType actually used and recommended in the customer facing doc, but if following the oak doc the primary type is oak:QueryIndexDefinition and therefore picked up in the index printer.
Uh oh!
There was an error while loading. Please reload this page.
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.
But if one uses jcr:primaryType: oak:QueryIndexDefinition, we now end up with a duplicate key /oak:index/diff.index, so maybe worth changing the doc.
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.
agree. @thomasmueller , I will also create a small PR to change the docs.