aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArun Isaac2023-09-25 23:43:23 +0100
committerArun Isaac2023-09-25 23:49:38 +0100
commit4b0ce31c5f139d371af1b063f83cf980e06fabaf (patch)
tree91166071aecdf4ccc38b7edba4c12ef68ccde554
parentcc386c2765e0fd705fee8f26fcb13aa9907f84db (diff)
downloadrent-in-london-4b0ce31c5f139d371af1b063f83cf980e06fabaf.tar.gz
rent-in-london-4b0ce31c5f139d371af1b063f83cf980e06fabaf.tar.lz
rent-in-london-4b0ce31c5f139d371af1b063f83cf980e06fabaf.zip
Ensure atomic writes to cache.
* rent.scm (call-with-atomic-output-file): New function. (http-get*): Use call-with-atomic-output-file instead of call-with-output-file.
-rw-r--r--rent.scm20
1 files changed, 18 insertions, 2 deletions
diff --git a/rent.scm b/rent.scm
index 3fe8d94..7258c5e 100644
--- a/rent.scm
+++ b/rent.scm
@@ -1,5 +1,5 @@
;;; rent-in-london --- Shortlist houses to rent in London
-;;; Copyright © 2022 Arun Isaac <arunisaac@systemreboot.net>
+;;; Copyright © 2022, 2023 Arun Isaac <arunisaac@systemreboot.net>
;;;
;;; This program is free software: you can redistribute it and/or
;;; modify it under the terms of the GNU General Public License as
@@ -61,6 +61,22 @@
(define %tfl-base-url
"https://api.tfl.gov.uk")
+(define (call-with-atomic-output-file filename proc)
+ "Open @var{filename} for output and pass the open port to
+@var{proc}. Writes to @var{filename} are guaranteed to be atomic."
+ (let* ((temporary-port (mkstemp "rent-XXXXXX"))
+ (temporary-filename (port-filename temporary-port)))
+ (dynamic-wind
+ (const #t)
+ (lambda ()
+ (call-with-port temporary-port
+ (lambda _
+ (proc temporary-port)
+ (fsync temporary-port)))
+ (rename-file temporary-filename filename))
+ (lambda ()
+ (false-if-exception (delete-file temporary-filename))))))
+
(define (json-ref scm . keys)
(match keys
((key other-keys ...)
@@ -207,7 +223,7 @@
(> (current-time)
(+ (stat:mtime (stat cache-file))
cache-live-time))))
- (call-with-output-file cache-file
+ (call-with-atomic-output-file cache-file
(cut put-bytevector <> (http-get-follow uri))))
;; Return contents of cache.
(call-with-input-file cache-file