Skip to content

Collections: search in book content#13139

Merged
Frenzie merged 15 commits into
koreader:masterfrom
hius07:coll-search-content
Feb 9, 2025
Merged

Collections: search in book content#13139
Frenzie merged 15 commits into
koreader:masterfrom
hius07:coll-search-content

Conversation

@hius07

@hius07 hius07 commented Jan 25, 2025

Copy link
Copy Markdown
Member

Rather slow, average about 1.5 s per book on Kindle Voyage.

1


This change is Reviewable

@poire-z

poire-z commented Jan 25, 2025

Copy link
Copy Markdown
Contributor

Mhhh, not fond of having that.
In any case, if it is not yet wrapped by Trapper, I think it should, so one can interrupt opening the 45 books of his collection when he notices a typo or later assume that nothing will really come out.

I also have no real idea of the possible side effects with crengine with calling loadDocument (without render) and half loading it:
Would an (invalide) cache file be created on close ?
If this can be called while another EPUB is open, could it screw up that main EPUB rendering/cache/behaviour ? crengine does not really support having multiple documents open, even if it have code for that, there are a few global variables that a change in one would reflect in the other, having lots of hash mismatch causing rerendering or messups. Dunno how just calling loadDocument affects that.
You're lucky that findText() works on a half loaded document :)

@hius07

hius07 commented Jan 25, 2025

Copy link
Copy Markdown
Member Author

if it is not yet wrapped by Trapper, I think it should

It is.

crengine does not really support having multiple documents open

Can be disabled if Collections are opened over reader.

@Frenzie

Frenzie commented Jan 25, 2025

Copy link
Copy Markdown
Member

Rather slow, average about 1.5 s per book on Kindle Voyage.

Sounds quite fast really, in the sense that maybe the actual searching doesn't add much on top of the opening.

@hius07

hius07 commented Jan 25, 2025

Copy link
Copy Markdown
Member Author

In the worst scenario (string not found) it took about 2.5 min to scan a mixed collection of 90 books (pdf, epub, fb2, fb2.zip).

@hius07

hius07 commented Jan 25, 2025

Copy link
Copy Markdown
Member Author

having lots of hash mismatch causing rerendering

If a collection content search has been done, then any book opened and closed, then the next search causes CRE warning "cached rendering is invalid" in crash.log for books in the collection.
I saw a trick with tmp cache in the CoverBrowser BookInfoManager that is purged after the job.
But if we make another search (without opening a book) the previous cache may be useful, I don't want to delete it.
(I would like to suppress the CRE warning)

@poire-z

poire-z commented Jan 25, 2025

Copy link
Copy Markdown
Contributor

If a collection content search has been done, then any book opened and closed

You mean opened and closed as book opened by the user for rendering and reading ? In which case, I guess it's normal: your search loadDocument would save a cached with no or default rendering properties saved - and when the book is opened for reading, a rerendering may happen, and the cache saved with the rendering props - and on next search loadDocument, these don't match the defaults.

(I would like to suppress the CRE warning)

If the warning happened on real user book opening, it should stay.
What you could try is explicitely, in your search, asking for the cache to not be created/saved, with self.ui.document:invalidateCacheFile() - haven't tested if it would just not create it or save it, please do so we know it's a solution.

I saw a trick with tmp cache in the CoverBrowser BookInfoManager that is purged after the job.
But if we make another search (without opening a book) the previous cache may be useful, I don't want to delete it.

Well, you could do that, but you will end up with a /cache/searchcr3cache that will be huge and stick - you would not want to set a limit like we do for the regulat cr3cache or coverbrowser ones, as these don't need to re-meet the books, while you do. If they start being removed because of some limits when you search books, on your next search, you will not find earlier ones, so recreate them, purging later ones, needing to actually reload all of them...
All this just to be able to if found then return true end and adding the book to the list without seeing anything about the actual matches, that the user will have to open to do the search in it again to may be see the match is crap...

I still think this PR is a bad idea :) the code is small, so you may add it - but let the user leave with the limitations (slow, no cache, just found=true/false), he probably won't use it once he sees how not really helpful it is, so no need for us to maintain another cache and risk cache/rendering issues with real book openings.

@hius07

hius07 commented Jan 25, 2025

Copy link
Copy Markdown
Member Author

CRE cache really speeds up searching. Opening the Reader invalidates it, but anyway it is useful for several consecutive searches, I'd like to keep it.

Searching the library for a string in books is a frequent request. Yes, it's slow without indexing, but it works.

@Frenzie

Frenzie commented Jan 25, 2025

Copy link
Copy Markdown
Member

Opening the Reader invalidates it, but anyway it is useful for several consecutive searches, I'd like to keep it.

That's fine, but does that imply the opposite is true as well? That seems more bothersome.

@hius07

hius07 commented Jan 25, 2025

Copy link
Copy Markdown
Member Author

Fair point.

@hius07

hius07 commented Jan 25, 2025

Copy link
Copy Markdown
Member Author

As far as I can see, "search in content" doesn't affect the main CRE cache.
Newly opened book has a cache file with extension .1.cr3.
"Search in content" creates a cache file of the same name with extension .0.cr3.

Reopening a book in Reader after "search in content" of this book doesn't require rerendering, the main cache remains good.

@poire-z

poire-z commented Jan 25, 2025

Copy link
Copy Markdown
Contributor

As far as I can see, "search in content" doesn't affect the main CRE cache.
Newly opened book has a cache file with extension .1.cr3.
"Search in content" creates a cache file of the same name with extension .0.cr3.
Reopening a book in Reader after "search in content" of this book doesn't require rerendering, the main cache remains good.

Feels like luck :) and you mentionned you have had some CRE WARNING previously.
The 0 or 1 comes from:
int flag = ( format==2 && getDocFlag(DOC_FLAG_PREFORMATTED_TEXT) ) ? 1 : 0;
So, a bit of luck if you get 0 when not setting anything, and we get 1 for books because we probably set this flag by default:

frontend/apps/reader/modules/readertypeset.lua:    self.txt_preformatted = config:readSetting("txt_preformatted")
frontend/apps/reader/modules/readertypeset.lua:                         or G_reader_settings:readSetting("txt_preformatted")
frontend/apps/reader/modules/readertypeset.lua:    self.ui.document:setTxtPreFormatted(self.txt_preformatted)
frontend/document/credocument.lua:function CreDocument:setTxtPreFormatted(enabled)
frontend/document/credocument.lua:    logger.dbg("CreDocument: set txt preformatted", enabled)
frontend/document/credocument.lua:    self._document:setIntProperty("crengine.file.txt.preformatted", enabled)

Anyway, this feels too risky.
To avoid strange issues later when a user will be using your feature and won't tell us when he opens an issue about some EPUB messup, if you really want that, I would like that

  1. you indeed use another cr3cache directory (whether you tidy it or let it fill up)
  2. you execute your loadDocument in a ffiutil.runInSubProcess() - so there's no chance it mess the current process crengine (it's a quite a bit more work... but that's what I felt was the best for any behind-the-scene crengine risky stuff like in coverbrowser/bookinfomanager, readerrolling for partial rendering, readerthumbnail to get page images after tweaking some crengine settings - and you avoid some memory usage/leaks by having all these loadDocument in individual processes that are cleaned up when they die).

@hius07

hius07 commented Jan 25, 2025

Copy link
Copy Markdown
Member Author

All search is under Trapper:dismissableRunInSubprocess.
"Search in content" is disabled if Collection is opened over Reader.

@poire-z

poire-z commented Jan 25, 2025

Copy link
Copy Markdown
Contributor

All search is under Trapper:dismissableRunInSubprocess.

OK, so this might solve my 2. and avoid messing with the current crengine (even if no book is open, we may have crengine loaded with our default or user settings we don't re set on further openings).

"Search in content" is disabled if Collection is opened over Reader.

OK, but you don't want to mess with the cache of any previously open book, and have strage stuff (or cache rendering is invalid, or even the DOM could be bad if you don't loadDocument with the same flat/book/web render mode).
So, you either need to be sure that you don't save a cache (please try my self.ui.document:invalidateCacheFile() just so we know if this works to not write any cache, so no .0.cr3 in your current setup).
Or you use a tmp/search cr3cache so any half-loaded cache file does not interfere with real book openings caches.

@hius07

hius07 commented Jan 25, 2025

Copy link
Copy Markdown
Member Author

Sorry, I didn't mention. I'm thinking about the search cache destiny.

@hius07

hius07 commented Jan 26, 2025

Copy link
Copy Markdown
Member Author

CRE cache is not created in loadDocument, it is created in findText.
Calling document:invalidateCacheFile() before cache creation causes segmentation fault.

Anyway, I decided to disable the cache in search. The cache becomes invalid on opening the Reader, i.e. it does not live long. Searching in the whole library will cause huge storage writing of cache files for all books, not good.
Searching in content is slow by design (without pre-indexing), the cache would not change the situation remarkably.

Comment on lines +882 to +883
if document.loadDocument then -- CRE
if not self.is_cre_cache_disabled then

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested comment:

-- We will be half-loading documents and may mess with crengine's state.
-- Fortunately, this is run in a subprocess, so we won't be affecting the
-- main process's crengine state or any document opened in the main
-- process (we furthermore prevent this feature when one is opened).
-- To avoid creating half-rendered/invalide cache files, it's best to disable
-- crengine saving of such cache files.

(Looks like you went back to comment-less coding :) there's not a single one in this PR :/)

@hius07

hius07 commented Jan 26, 2025

Copy link
Copy Markdown
Member Author

Sad figures, average per book:
disabled cache: 4.0 s
enabled cache, first call: 3.5 s
enabled cache, next calls: 1.8 s

@hius07

hius07 commented Jan 26, 2025

Copy link
Copy Markdown
Member Author

Reduced to 3.0 s.

@hius07

hius07 commented Jan 26, 2025

Copy link
Copy Markdown
Member Author

3.0 s is an average time for a mixed library.
Actually, for epub the search is quicker than for pdf.
CRE returns true on the first occurrence, pdf searches all matches in a document.

Comment on lines +945 to +947
if is_cre_cache_disabled then
require("document/credocument").cacheInit()
end

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If I understand it right, here we are in the main process.
You will set is_cre_cache_disabled=true in isFileMatch(), which is run in the subprocess. So, the is_cre_cache_disabled in the main process will not be affected: the 2 processes are independant and don't share any variable/memory.
You don't even need to re-enable the cache: once the subprocess dies, it's gone, whatever the state of things is, we don't care. The main process never gets it disabled.

@hius07

hius07 commented Jan 27, 2025

Copy link
Copy Markdown
Member Author

Thanks. If engine has been inited before search, the cache is affected by the search, need to restore.
I've got
./luajit: frontend/document/doccache.lua:72: attempt to compare two nil values

EDIT: but it's another cache. Looking into it.

EDIT2: main CRE cache is not affected by the search, I'm reverting last changes.

@hius07

hius07 commented Jan 27, 2025

Copy link
Copy Markdown
Member Author

Reverted.

The crash with DocCache occurred because I deleted the whole .cache folder with the latest page cached images:

-- Serialize the most recently displayed page for later launch
DocCache:serialize(self.document.file)

By the way, we do not use these cached images for cre documents but create them.

Comment thread frontend/document/credocument.lua Outdated
Comment on lines +102 to +105
function CreDocument.disableCache()
cre = cre or CreDocument:engineInit()
cre.initCache("", 0, true, 40)
end

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

You plan to use this for other things ?
Depending on the need, other use cases may want to use other parameters, so I'd somehow like to have that in the call site (like we do in the other places we tweak it).
Anyway, if keeping it, add a comment:
-- To be used only when in a subprocess to not interfere with opened books caches

@poire-z

poire-z commented Jan 27, 2025

Copy link
Copy Markdown
Contributor

By the way, we do not use these cached images for cre documents but create them.

Somehow, I don't have any, and only saw them (ie. koreader/cache/40f7e63bd12a22cf8b7640b81b16c7fa)) when I open a PDF.
(Looking at the code, it seems there's no paging/rolling test, so dunno why nothing gets written, may be because the cache slots are empty?)

@hius07

hius07 commented Jan 27, 2025

Copy link
Copy Markdown
Member Author

DocCache is not created by credocument, nothing is written when ReaderUI calls

function DocCache:serialize(doc_path)
if not self.disk_cache then
return
end

(I haven't looked into .cache folder for a while, maybe some cached pages occurred there during my experiments. In any case, I cannot reproduce the crash of DocCache anymore)

@Frenzie

Frenzie commented Feb 9, 2025

Copy link
Copy Markdown
Member

@poire-z happy with it?

@poire-z

poire-z commented Feb 9, 2025

Copy link
Copy Markdown
Contributor

Not really, I still think it is a bad idea - but as it's limited to Collections, hopefully we won't have much feedback and issues, so go ahead merging.

@Frenzie Frenzie added this to the 2025.02 milestone Feb 9, 2025
@Frenzie Frenzie merged commit aa1e96f into koreader:master Feb 9, 2025
@hius07 hius07 deleted the coll-search-content branch February 11, 2025 12:14
0xstillb pushed a commit to 0xstillb/koreader-thai that referenced this pull request May 9, 2026
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.

3 participants