Watching a statement while it runs - #22
Merged
Merged
Conversation
rowsRead is how far the statement running now has got, and progress is a timer around it. A statement that takes a minute is one somebody is sitting in front of, and this client had nothing to tell them while it ran. The count is read the way `open` is, as an atomic beside the connection's lock rather than a question through it, so it answers on the loop's thread while the statement holds the lock on a threadpool thread. It counts rows read out of storage rather than rows answered, because the statement somebody is waiting on is exactly the one that reads a hundred million rows to answer one. The watch itself is JavaScript, in zudb.cjs beside stream. A timer is all it takes, since the loop is free while the statement runs, and nothing calls into JavaScript from the thread doing the scanning: a thread safe function there would be a scan that stops to talk to the loop. The callback runs only when the count has moved, so a watch on an idle connection says nothing and one nobody stopped is not a callback ten times a second forever, and the timer does not hold the process open. One thing turned up on the way. The counter was never put back down between statements here, so it had been counting a connection's whole life rather than one statement, which is neither what Python does nor what the shell does. It is cleared now where the connection becomes a statement's, which is the one moment that can be done without racing the getter, and the three places that happens are the query, the stream and the profile.
This was referenced Aug 19, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
rowsReadis how far the statement running now has got, andprogressis a timer around it. A statement that takes a minute is one somebody is sitting in front of, and this client had nothing to tell them while it ran.The count is read the way
openis, as an atomic beside the connection's lock rather than a question through it, so it answers on the loop's thread while the statement holds the lock on a threadpool thread. It counts rows read out of storage rather than rows answered, because the statement somebody is waiting on is exactly the one that reads a hundred million rows to answer one.The watch itself is JavaScript, in
zudb.cjsbesidestream. A timer is all it takes, since the loop is free while the statement runs, and nothing calls into JavaScript from the thread doing the scanning: a thread safe function there would be a scan that stops to talk to the loop. The callback runs only when the count has moved, so a watch on an idle connection says nothing and one nobody stopped is not a callback ten times a second forever, and the timer does not hold the process open. It is stopped bystop()or by leaving the scope of theusing, and the interval is{ everyMs }with a tenth of a second by default.One thing turned up on the way. The counter was never put back down between statements here, so it had been counting a connection's whole life rather than one statement, which is neither what Python does nor what the shell does. It is cleared now where the connection becomes a statement's, which is the one moment that can be done without racing the getter, and the three places that happens are the query, the stream and the profile. So
conn.rowsReadafter a statement is what that statement cost.Ten tests, including that the number moves during the statement rather than after it, that a watch on an idle connection stays quiet, that a stopped one stops, that a
usingstops it at the end of the block, and that a program with a watch nobody stopped still exits. The whole suite is green locally, with the types, the API report and the formatting.