
Is there a way to create a read-only text%
? (I thought I’d done this already, but I can’t seem to find out how.)

Did you subclass text% and bind “edit” functions to do-nothing?

Maybe this - though I have to admit I haven’t used it. > > 4.5 In-Source Documentation > The https://docs.racket-lang.org/scribble/srcdoc.html#%28mod-path._scribble%2Fsrcdoc%29\|scribble/srcdoc and https://docs.racket-lang.org/scribble/srcdoc.html#%28mod-path._scribble%2Fextract%29\|scribble/extract libraries support writing documentation within the documented code along with an export contract, similar to using JavaDoc. With this approach, a single contract specification is used both for the run-time contract and the documentation of an exported binding. https://docs.racket-lang.org/scribble/srcdoc.html

Use the lock
method.

Ah, there it is, thanks @ryanc!

You might be able to get local-expand
plus parameterize
to solve this problem. But I think it’s bad that a macro prints to stderr. Possible solutions include changing lexer
to log at 'warning
— or to log at 'error
but also add a declaration to lexer
to suppress the output.

Yep, there’s a PR that does exactly that: https://github.com/racket/parser-tools/pull/6

Any windows user out there ? I think I have a way to extend the ‘Open terminal here’ function in quickscripts-extra library of scripts for DrRacket but I need help testing as I don’t have a windows machine. (code in thread)

This is the code
```#lang racket/base
(require racket/system
racket/path
quickscript)
(script-help-string "Open a terminal in the current directory.")
(define-script open-terminal
#:label "Open terminal"
#:menu-path ("&Utils")
#:os-types (unix macosx windows)
#:output-to message-box
(case (system-type 'os)
[(unix) (λ (str #:file f)
(define dir (path->string (path-only f)))
(system (string-append "gnome-terminal"
" --working-directory=\"" dir "\""
" -t \"" dir "\""
"&"))
#f)]
[(macosx) (λ (str #:file f)
(define dir (path->string (path-only f)))
(define osascriptdir (string-append
(path->string (find-system-path 'pref-dir))
"quickscript/user-scripts/"))
(system (string-append "osascript -e 'tell app \"Terminal\" to do script \"cd \\\"" dir "\\\"\"'" ))
#f)]
[(windows) (system (string-append "cmd /c start cmd.exe /K \"cd " dir))]
))```

...
[(windows)
(λ (str #:file f)
(define dir (path->string (path-only f)))
(system (string-append "cmd /c start cmd.exe /K \"cd " dir)))]

does that work?

I’m not sure yet. I seem to be in the racket program dir, not in the dir of the file

also, afterwards I’m left with an extra (unresponsive) command window

ok, at least it figures out the right directory for something else than the script itself

Maybe use shell-execute
for windows (only) instead.

(system (string-append "start cmd.exe /K \"cd " dir))
gives the same result (still the extra window…)

I’m a web server. I serve multiple clients. Each client is identified by an integer. Clients consume a database that changes once every hour. I want to save in memory the database I read off the disk. Each client has a different database, so I must memorize them all. (Few clients, though, and I know how many there are. The clients are not web users. The clients are Javascript-based web applications.)
I thought of keeping a hash table in memory where each pair is indexed by the client-id-integer. But I just read on the https://docs.racket-lang.org/reference/hashtables.html#%28elem._%28caveat._concurrency%29%29\|documentation that…
> if a thread is terminated while applying https://docs.racket-lang.org/reference/hashtables.html#%28def._%28%28quote._~23~25kernel%29._hash-ref%29%29\|hash-ref, https://docs.racket-lang.org/reference/hashtables.html#%28def._%28%28quote._~23~25kernel%29._hash-ref-key%29%29\|hash-ref-key, https://docs.racket-lang.org/reference/hashtables.html#%28def._%28%28quote._~23~25kernel%29._hash-set%21%29%29\|hash-set!, https://docs.racket-lang.org/reference/hashtables.html#%28def._%28%28quote._~23~25kernel%29._hash-remove%21%29%29\|hash-remove!, https://docs.racket-lang.org/reference/hashtables.html#%28def._%28%28lib._racket%2Fprivate%2Fmore-scheme..rkt%29._hash-ref%21%29%29\|hash-ref!, or https://docs.racket-lang.org/reference/hashtables.html#%28def._%28%28lib._racket%2Fprivate%2Fmore-scheme..rkt%29._hash-update%21%29%29\|hash-update! […, then] all current and future operations on the hash table may block indefinitely. Each web request is served by a different thread (as far as I know). (I’m using web-server/servlet
.) So I think I can’t correctly use a hash table as a solution here. Then I have no idea what to do. How do you guys handle this?

@anything you shouldn’t have threads being terminated in that situation

threads are terminated with kill-thread
— don’t use that and you should be ok

That’s excellent news! Thank you! (I suddenly feel much better.)

thread termination is an abrupt operation that is mostly not needed

yes, with shell-execute there is no extra window: [(windows)
(λ (str #:file f)
(define dir (path->string (path-only f)))
;(system (string-append "start cmd.exe /K \"cd " dir))
(shell-execute #f "cmd.exe" "" dir 'sw_shownormal))]

I got the impression that the issue is not so much about threads being killed but rather about them running to completion and stopping normally.

and it opens correctly in dir
?

no, if that happens they will release the lock

yes

because they will have (by definition) finished doing hash-ref

Right, but I got the impression that the cache was supposed to be independent of the request cycle altogether.

cleaned up version

#lang racket/base
(require racket/system
racket/path
quickscript)
(script-help-string "Open a terminal in the current directory (linux and macosx only).")
(define-script open-terminal
#:label "Open terminal here"
#:menu-path ("&Utils")
#:os-types (unix macosx)
#:output-to message-box
(case (system-type 'os)
[(unix)
(λ (str #:file f)
(define dir (path->string (path-only f)))
(system (string-append "gnome-terminal"
" --working-directory=\"" dir "\""
" -t \"" dir "\""
"&"))
#f)]
[(macosx)
(λ (str #:file f)
(define dir (path->string (path-only f)))
(system
(string-append "osascript -e 'tell app \"Terminal\" to do script \"cd \\\"" dir "\\\"\"'" ))
#f)]
[(windows)
(λ (str #:file f)
(define dir (path->string (path-only f)))
;(system (string-append "start cmd.exe /K \"cd " dir))
(shell-execute #f "cmd.exe" "" dir 'sw_shownormal))]))

I mean: if, for a period of say 10 minutes, there are no requests, that doesn’t mean you want to drop the cache on the floor, right @anything?

(remove the dead code maybe, and update the help-string before submitting)

(But maybe I misunderstood.)

doing now

thank you @bedeke

Yes, I will never drop the cache. (Though every hour I will update all buckets.)

Right, so you don’t want its reachability to be based on any particular request.

What do you mean by “reachability”?

In terms of garbage collection, I mean.

Yes, there should be no garbage collection. The hash table (that is, the cache) will be held in the web-server’s main thread to be consumed by all threads serving web users. (I plan to use a https://docs.racket-lang.org/reference/boxes.html\|box for that. That is, the hash table will be kept in a box in the web server’s main thread.)

You know — I think I did misunderstand.

I thought you were suggesting that the cache would be established (and kept reachable) by request threads, but that’s not what you’re proposing, so you’re good.

:slightly_smiling_face:

Alright. I confess I did not quite see what you were seeing. (I’m a newbie here, so you might see a thousand things ahead of me.)

@idel_martinez has joined the channel

@anything have you definitely found the cache is necessary? If it’s mainly just a copy of the database information, you may find the database handles the caching well enough.


My database is sqlite and I think I can speed things up considerably by saving a JSON string and not compute jsexpr->string at every request. I will compare the times and be sure of the improvement when I’m done. (This is an experiment.) Each client consumes its entire set of records so that Javascript can let the web users do the filtering, paging et cetera. Each string ends up being around 721KiB.

On first look it seems memcached is what I’m going to implement here. :slightly_smiling_face:

You could compute the JSON string once per hour when the data changes, and store the JSON string in a text column in the database. And advantage of this approach (or memcached) is the ability to have multiple web server processes, e.g. one per core, w/o duplicating all of the data in each process.

You know, you’re totally right! (That’s what I’ll do. Thanks for this great idea.) My “hash table” will just be another little table in the database and the whole thing is simplified. That’s perfect.

If you’re going for performance, two things to watch out for:
• the SQLite adapter is implemented using the FFI so calling an SQLite function will block Racket’s event loop (meaning that if you have a long-running query, no other requests will be served during that time); to get around this pass #:use-place #t
to to have it run the SQLite functions in a separate place (OS thread) — this will slow down really fast queries, but it’ll have the effect that slow queries can’t affect the performance of the whole server • make sure you set content-length headers on your responses, otherwise the server will use chunked transfer encoding.

Very interesting information. I suppose the Racket web server (web-server/servlet) sets the content-length automatically? I will check this.

Good to know @popa.bogdanp - I presume this is not the case for postgres, I think the db package uses native wire protocol for that, right?

@anything it does not. You have to set it yourself if you want to avoid chunked-transfer encoding.

@badkins yes, the postgres adapter is implemented in pure Racket so it doesn’t have this problem.

Thanks! This could in fact be the performance issue I’d like to optimize. I will check this first.

@popa.bogdanp just out of curiosity, is chunked encoding necessarily a problem? Wouldn’t it allow the writing of the response to be done concurrently with the web server outputting it to the client?

Particularly with large JSON strings as in Any’s case?

I suppose it’s easy enough to just try it both ways.

For most applications it isn’t, and it’s definitely something I’d measure, but it is for sure slower because of all the extra buffering it entails.

When I was looking at the TechEmpower benchmarks throughput using chunked encoding was about half that of just writing the data to the client immediately. (in the JSON and plaintext benchmarks)

So that benchmark isn’t quite accurate for the Racket Web Server then? (I mean it seems about half-inaccurate.)

I’ve made some updates to it in the past few weeks so the next round will be more accurate.

Oh, are you the one doing that benchmark?

Cool.

Here’s a thread on racket-users
about it and the current limitations: https://groups.google.com/g/racket-users/c/fHsM4kQb22c/m/rdF9cQJamNEJ

Looks like Apple’s switch to ARM processors <https://www.theverge.com/2020/6/22/21295475/apple-mac-processors-arm-silicon-chips-wwdc–2020|is official>

I recall some discussion recently, but I don’t recall any specific consequences of this for Racket. I remember running Racket on my Raspberry Pi just fine, but that’s a 32-bit ARM. Does Racket BC run on 64-bit ARM currently, but Chez Scheme still needs to be ported to ARM for Racket CS ?

I believe that’s correct

Time to go out and get your 16" macbook pros before they switch :slightly_smiling_face: I’m fairly satisfied with mine from a hardware perspective, but MacOS Catalina has a fair number of issues :disappointed:

Time to go out and get a top-of-the line raspberry pi4 (64 bit arm?)

Others have stepped up for an Arm 64 port, but my Pi 4 arrives in a couple of days. I expect the improved hardware will make it nicer to fill in the remaining piece for 32-bit Arm Racket CS (which is thread support to enable places + futures).