diff options
| author | EuAndreh <eu@euandre.org> | 2025-12-04 06:17:50 -0300 |
|---|---|---|
| committer | EuAndreh <eu@euandre.org> | 2025-12-04 06:25:04 -0300 |
| commit | 13edba0fa2bd4c3847160809499ce837f52d1264 (patch) | |
| tree | 73c1df9c4e2d1b36102eddfffb52babb98c5d406 | |
| parent | etc/transactor.properties.tmpl: Default to "tmp" for data-dir (diff) | |
| download | datomic-main.tar.gz datomic-main.tar.xz | |
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | Makefile | 12 | ||||
| -rwxr-xr-x | bin/datomic.in | 85 | ||||
| -rw-r--r-- | etc/backup.clj | 45 |
4 files changed, 140 insertions, 3 deletions
@@ -1,4 +1,5 @@ bin/transactor +bin/datomic *.db *.db-shm *.db-wal @@ -39,11 +39,11 @@ include deps.mk sources = \ - $(sources.sh) \ derived-assets = \ bin/transactor \ + bin/datomic \ side-assets = \ @@ -82,8 +82,13 @@ install: all '$(DESTDIR)$(SYSCONFDIR)' \ '$(DESTDIR)$(JAVADIR)' \ - cp bin/transactor '$(DESTDIR)$(BINDIR)' - cp etc/init.sql etc/logback.xml etc/transactor.properties.tmpl \ + cp bin/transactor bin/datomic \ + '$(DESTDIR)$(BINDIR)' + cp \ + etc/backup.clj \ + etc/init.sql \ + etc/logback.xml \ + etc/transactor.properties.tmpl \ '$(DESTDIR)$(SYSCONFDIR)' cp share/java/datomic/*.jar \ '$(DESTDIR)$(JAVADIR)' @@ -95,6 +100,7 @@ install: all uninstall: rm -rf \ '$(DESTDIR)$(BINDIR)'/transactor \ + '$(DESTDIR)$(BINDIR)'/datomic \ '$(DESTDIR)$(SYSCONFDIR)' \ '$(DESTDIR)$(JAVADIR)' \ diff --git a/bin/datomic.in b/bin/datomic.in new file mode 100755 index 0000000..2f60912 --- /dev/null +++ b/bin/datomic.in @@ -0,0 +1,85 @@ +#!/bin/sh +set -euo pipefail + + +usage() { + cat <<-'EOF' + Usage: + datomic backup DBFILE TODIR + datomic gc DBFILE + EOF +} + + +ACTION="${1:-}" +DBFILE="${2:-}" +TODIR="${3:-}" + +if [ -z "$ACTION" ]; then + echo 'Missing ACTION.' >&2 + usage >&2 + exit 2 +fi + +if [ -z "$DBFILE" ]; then + echo 'Missing DBFILE.' >&2 + usage >&2 + exit 2 +fi + +if [ "$ACTION" = 'backup' ] && [ -z "$TODIR" ]; then + echo 'Missing TODIR.' >&2 + usage >&2 + exit 2 +fi + + + +lastroot() ( + cd "$TODIR"/datomic/roots + find * | sort -n | tail -n1 +) + +backupcmd() { + java \ + -server \ + -Xms4g \ + -Xmx4g \ + --class-path '@SYSCONFDIR@/:@JAVADIR@/*' \ + clojure.main \ + -m backup \ + "$@" +} + + +case "$ACTION" in + (backup) + backupcmd backup datomic:sql://app?jdbc:sqlite:"$DBFILE" file:"$TODIR"/datomic + backupcmd verify file:"$TODIR"/datomic true "$(lastroot)" + sqlite3 "$DBFILE" ".backup '$TODIR/sqlite.db'" + { + sqlite3 "$DBFILE" .dump > "$TODIR"/dump.sql.next + mv "$TODIR"/dump.sql.next "$TODIR"/dump.sql + } + { + sqlite3 "$TODIR"/restored.db < @SYSCONFDIR@/init.sql > /dev/null + backupcmd restore file:"$TODIR"/datomic datomic:sql://app?jdbc:sqlite:"$TODIR"/restored.db + } + ;; + (gc) + exec java \ + -server \ + -Xms4g \ + -Xmx4g \ + --class-path '@SYSCONFDIR@/:@JAVADIR@/*' \ + clojure.main \ + -m datomic.tools.gc-db \ + datomic:sql://app?jdbc:sqlite:"$DBFILE" \ + "$(date --date="$(date +'%Y-%m-01') - 3 months" -Is)" + ;; + (*) + printf 'Bad ACTION: "%s"\n' "$ACTION" >&2 + usage >&2 + exit 2 + ;; +esac diff --git a/etc/backup.clj b/etc/backup.clj new file mode 100644 index 0000000..ae4a380 --- /dev/null +++ b/etc/backup.clj @@ -0,0 +1,45 @@ +(ns backup + (:require [clojure.edn :as edn] + [datomic.require :as req] + [datomic.cli :as cli])) + +(def commands + "Map of command names to descriptions of command arguments." + {"backup" + {:f 'datomic.backup-cli/backup + :named #{{:long-name :from-db-uri :required true :doc "URI for backup source"} + {:long-name :to-backup-uri :required true :doc "URI for backup destination"}} + :positional [:from-db-uri :to-backup-uri]} + "list" + {:f 'datomic.backup-cli/list-backups + :named #{{:long-name :backup-uri :required true :doc "backup URI"}} + :positional [:backup-uri :to-db-uri]} + "verify" + {:f 'datomic.backup-cli/verify-backup + :named #{{:long-name :backup-uri :required true :doc "URI of backup"} + {:long-name :read-all :required true :doc "Verify that every segment is readable" :coerce #(boolean (edn/read-string %))} + {:long-name :t :required true :doc "Point in time (t) to verify" :coerce #(Long. %)}} + :positional [:backup-uri :read-all :t]} + "restore" + {:f 'datomic.backup-cli/restore + :named #{{:long-name :from-backup-uri :required true :doc "URI for restore source"} + {:long-name :to-db-uri :required true :doc "URI for restore destination"} + {:long-name :t :doc "Point in time (t) to restore, defaults to most recent" + :default nil :coerce #(Long. %)}} + :positional [:from-backup-uri :to-db-uri :t]}}) + +(defn -main + [& [command & cli-args]] + (if-let [{:keys [f named positional vararg]} (get commands command)] + (let [args (cli/parse-or-exit! command cli-args named positional vararg)] + (try + (when-let [result (req/require-and-run f args)] + (println result)) + (catch Throwable t + (.printStackTrace t) + (cli/fail (.getMessage t)))) + (when @cli/exit-after-command + (System/exit (if @cli/failed 1 0)))) + (binding [*out* *err*] + (println (str "Bad command: \"" command "\".")) + (System/exit 2)))) |
