[ 
https://issues.apache.org/jira/browse/TIKA-5057?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18141661#comment-18141661
 ] 

Tim Allison commented on TIKA-5057:
-----------------------------------

Bot comments on current state:

h3. Status

The review and refactor of the OneNote parser is in PR #3564. Summary of where 
it stands:

* *Current text only.* .one sections give each page's current revision, not 
every earlier revision and version-history snapshot. Metadata and attachments 
still come from all revisions. New {{one-note-parser}} config, both default 
false:
** {{includePageHistory}}: earlier revisions and saved page versions.
** {{includeDeletedContent}}: pages moved to the recycle bin; FSSHTTPB sections 
only.
* *Correctness:*
** Objects resolve within their own revision, which stops old and new text 
being mixed.
** File node lists end at the transaction log's committed count, which recovers 
text that 4.2.0 misses.
** Text cleanup: windows-1252 extended ASCII; no NULs or U+FFFC placeholders.
* *New output:*
** Pictures as {{<img>}}, OneNote's OCR text, handwriting recognition and 
hyperlinks.
** OneNote 2007 paragraph text, and table-of-contents sections.
** Encrypted sections fail with EncryptedDocumentException.
* *Limits:* bounded file node lists, walk visits and depth, and a document-wide 
budget on property values that scales with file size.

h3. Performance and GC

Four builds: 4.2.0, main just before TIKA-5055, main with TIKA-5055, and this 
PR. Wall time is the mean per parse; allocation, GC count and GC time are per 
run. All are summed over the files in each set. Machine load was 0.7–3.4 during 
the runs, so wall times are approximate; allocation and GC counts are not 
affected.

*17 OneNote test files in tika-parser-microsoft-module (15 .one, 2 FSSHTTPB), 
1,000 parses each* (the TIKA-5055 benchmark):

||Build||Wall||Allocated per parse||GC count||GC time||
|4.2.0|304 ms|1,029 MiB|6,533|12.7 s|
|main before TIKA-5055|298 ms|1,029 MiB|6,337|11.9 s|
|main with TIKA-5055|253 ms|1,003 MiB|4,791|7.1 s|
|this PR|28 ms|44 MiB|325|0.3 s|

*57 FSSHTTPB corpus files, 200 parses each:*

||Build||Wall||Allocated per parse||GC count||GC time||
|4.2.0|2,794 ms|2,313 MiB|6,351|121 s|
|main before TIKA-5055|2,678 ms|2,314 MiB|6,502|114 s|
|main with TIKA-5055|190 ms|519 MiB|734|0.7 s|
|this PR|182 ms|503 MiB|627|0.6 s|

* TIKA-5055 is what fixed FSSHTTPB. One 161 MB file dominates these totals; 
TIKA-5055 takes it from 1,951 MiB and 2.4 s per parse to 390 MiB and 142 ms. 
Without that file, the other 56 go from 363 MiB and 5.7 s of GC to 130 MiB and 
0.25 s; this PR brings them to 114 MiB and 0.21 s.
* For .one sections, the PR's gains come from {{OneNoteDirectFileResource}}. 
Every read of a few bytes allocated a new 8 KB transfer buffer and made at 
least one system call. Reads now come from a 64 KB window of the file. The tree 
walker also no longer builds a nested map of every node and property that 
nothing read, and {{ExtendedGUID.hashCode()}} no longer allocates.

*4 largest .one corpus files (18–41 MB), 3 parses each:*

||Build||Wall||Allocated per parse||GC time||
|4.2.0|1,677 ms|2,280 MiB|85 ms|
|main with TIKA-5055|1,514 ms|2,279 MiB|96 ms|
|this PR|3,854 ms|2,930 MiB|835 ms|

Large sections with many revisions cost more in this PR: about 2.5 times the 
wall time and 9 times the GC time of main. 4.2.0 stops reading their file node 
lists early: on the 41 MB section it sees 31 revisions and 1,590 objects, while 
this PR reads all 185 revisions and 56,333 objects. Lowering that means 
releasing deserialized objects during the parse, a structural change better 
done as a follow-up.

h3. Testing

* *Corpus:* 913 unique files: 804 sections and 109 table-of-contents files.
** Sources: Common Crawl, open-source repositories and test fixtures, and 
sections unpacked from .onepkg packages.
** Sections by format: 709 OneNote 2010–2016, 57 FSSHTTPB, 31 OneNote 2007, 6 
OneNote 2003, and 1 truncated.
** 877 parse with content. The rest are 13 encrypted, 12 with no content, 6 
OneNote 2003 files that fall back to the legacy text dump, and a few broken or 
synthetic files.
* *Replay:* every corpus file through the tika-fuzzing harness (TIKA-5060) in 
bytes, stream and path modes: 2,739 parses, no hangs, OOMs, crashes or 
unexpected exceptions, including in strict mode.
* *Fuzzing:* a one-hour coverage-guided Jazzer run of 
{{AutoDetectParserFuzzTest}}, seeded with 56 OneNote files: 417,088 executions, 
and no crashes, hangs or OOMs.

h3. Follow-ups

* OneNote 2007 inline pictures
* Handwriting recognition in FSSHTTPB sections
* Linking .one pictures to their attachment data
* Marking page-history text in .one output
* Checking whether .one sections keep deleted pages
* A small test file with a deleted page
* Lower memory for large multi-revision sections
 

> General improvements to onenote parser
> --------------------------------------
>
>                 Key: TIKA-5057
>                 URL: https://issues.apache.org/jira/browse/TIKA-5057
>             Project: Tika
>          Issue Type: Task
>            Reporter: Tim Allison
>            Priority: Trivial
>
> When I have extra tokens, I'll have an agent focus on a parser at a time for 
> robustness and simplicity. Let's start with onenote. CC [~henrylindemanglean]
> :robot: swarm recommends:
> {noformat}
>   Native .one path (the common format, unrelated to TIKA-5055):
>   1. Exponential parse on shared child lists (OneNotePtr:714). A file-node 
> list referenced twice is parsed twice. Only the current path is checked for 
> cycles, so a crafted file of a few KB blows up as 2^depth. Three reviewers 
> found this independently.
>   2. Exponential tree walk (OneNoteTreeWalker:648). The same shape: shared 
> objects are walked once per reference path. Each visit also builds and keeps 
> a HashMap of decoded properties, which OneNoteParser:144 throws away.
>   3. Wrong references, lost text (OneNotePtr:1185). The OID/OSID/ContextID 
> stream position is copied to a local variable and never written back. Every 
> reference property starts again at stream[0], so later references are never 
> walked. It also removes the
>      cap on reference counts.
>   4. Duplicate text in real files (OneNoteTreeWalker:569-592). Reproduced: 
> testOneNote2.one produces 176 paragraphs, 105 of them "Untitled picture.png". 
> Image filenames and TextExtendedAscii text are never deduplicated and ignore 
> the revision filter.
>   5. Unchecked counts and budgets (OneNotePtr:838, :518, :809):
>      - ObjectInfoDependencyOverrideData counts are unbounded.
>      - The global-ID cap applies per node, with no total.
>      - A negative FileDataStoreObject length gets through.
>   6. Smaller issues:
>      - Embedded file data is read in full before shouldParseEmbedded is asked 
> (OneNoteTreeWalker:435).
>      - The UTF-16 NUL terminator stays in author names and image filenames.
>   Legacy string dump, used whenever a parse falls back 
> (OneNoteLegacyDumpStrings:95):
>   - Never resets its buffer at 1 MB boundaries. A long run is emitted again 
> at every boundary, so work grows quadratically and normal files over 1 MB get 
> duplicated text.
>   - Small bugs: it drops the last byte of each buffer, 
> Character.isWhitespace(i) tests the loop index instead of the character, and 
> split(" ") allocates one String per word.
>   Fallback after a partial walk (OneNoteParser:172, :197): on both paths, the 
> full legacy dump is added after whatever the failed walk already wrote, so 
> content appears twice.
>   FSSHTTPB:
>   - GUIDs are MD5 hashes, not decoded (BitReader:140, AdapterHelper:37). They 
> come from UUID.nameUUIDFromBytes. As a result:
>     - Encrypted sections are never detected; the check at 
> MSOneStoreParser:328 can't match.
>     - Embedded relationship IDs contain hashed GUIDs.
>   - Every cell mapping copies its whole revision chain 
> (MSOneStoreParser:362), so the cost grows with mappings × objects.
>   - Slow spots:
>     - removeSupersededObjects is O(n²) (:393).
>     - resourceInfoFromReferencingObject scans every object for each unnamed 
> blob (MSOneStorePackage:1140).
>     - hasUsablePicture copies a whole blob just to check it's non-empty 
> (:1118).
>   - Small port bugs:
>     - cProperties is read as signed, so values ≥ 0x8000 abort the parse.
>     - An undefined property type throws an NPE.
>     - StorageManifestSchemaGUID reads from offset 0 instead of the current 
> position.
>     - BitConverter's bounds check ignores the index.
>   Dead code:
>   - The serialize/write path: 65 files, about 970 lines.
>   - The FSSHTTPD chunking/build side.
>   - getContent() and its builders.
>   - Unreferenced classes: Error, PropertyIDType, RequestTypes, UMath.
>   - Debug print() methods and option branches that are never set.
> {noformat}



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

Reply via email to