all repos — honk @ b602d33e4b4c03dc9a1a172ec4a850152d4bc11b

my fork of honk

backupdb.go (view raw)

  1//
  2// Copyright (c) 2020 Ted Unangst <tedu@tedunangst.com>
  3//
  4// Permission to use, copy, modify, and distribute this software for any
  5// purpose with or without fee is hereby granted, provided that the above
  6// copyright notice and this permission notice appear in all copies.
  7//
  8// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 10// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 11// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 12// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 13// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 14// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 15
 16package main
 17
 18import (
 19	"database/sql"
 20	"fmt"
 21	"os"
 22	"time"
 23
 24	"strings"
 25)
 26
 27func qordie(db *sql.DB, s string, args ...interface{}) *sql.Rows {
 28	rows, err := db.Query(s, args...)
 29	if err != nil {
 30		elog.Fatalf("can't query %s: %s", s, err)
 31	}
 32	return rows
 33}
 34
 35func scanordie(rows *sql.Rows, args ...interface{}) {
 36	err := rows.Scan(args...)
 37	if err != nil {
 38		elog.Fatalf("can't scan: %s", err)
 39	}
 40}
 41
 42func svalbard(dirname string) {
 43	err := os.Mkdir(dirname, 0700)
 44	if err != nil && !os.IsExist(err) {
 45		elog.Fatalf("can't create directory: %s", dirname)
 46	}
 47	now := time.Now().Unix()
 48	backupdbname := fmt.Sprintf("%s/honk-%d.db", dirname, now)
 49	backup, err := sql.Open("sqlite3", backupdbname)
 50	if err != nil {
 51		elog.Fatalf("can't open backup database")
 52	}
 53	_, err = backup.Exec("PRAGMA journal_mode=WAL")
 54	for _, line := range strings.Split(sqlSchema, ";") {
 55		_, err = backup.Exec(line)
 56		if err != nil {
 57			elog.Fatal(err)
 58			return
 59		}
 60	}
 61	tx, err := backup.Begin()
 62	if err != nil {
 63		elog.Fatal(err)
 64	}
 65	orig := opendatabase()
 66	rows := qordie(orig, "select userid, username, hash, displayname, about, pubkey, seckey, options from users")
 67	for rows.Next() {
 68		var userid int64
 69		var username, hash, displayname, about, pubkey, seckey, options string
 70		scanordie(rows, &userid, &username, &hash, &displayname, &about, &pubkey, &seckey, &options)
 71		doordie(tx, "insert into users (userid, username, hash, displayname, about, pubkey, seckey, options) values (?, ?, ?, ?, ?, ?, ?, ?)", userid, username, hash, displayname, about, pubkey, seckey, options)
 72	}
 73	rows.Close()
 74
 75	rows = qordie(orig, "select honkerid, userid, name, xid, flavor, combos, owner, meta, folxid from honkers")
 76	for rows.Next() {
 77		var honkerid, userid int64
 78		var name, xid, flavor, combos, owner, meta, folxid string
 79		scanordie(rows, &honkerid, &userid, &name, &xid, &flavor, &combos, &owner, &meta, &folxid)
 80		doordie(tx, "insert into honkers (honkerid, userid, name, xid, flavor, combos, owner, meta, folxid) values (?, ?, ?, ?, ?, ?, ?, ?, ?)", honkerid, userid, name, xid, flavor, combos, owner, meta, folxid)
 81	}
 82	rows.Close()
 83
 84	rows = qordie(orig, "select convoy from honks where flags & 4 or whofore = 2 or whofore = 3")
 85	convoys := make(map[string]bool)
 86	for rows.Next() {
 87		var convoy string
 88		scanordie(rows, &convoy)
 89		convoys[convoy] = true
 90	}
 91	rows.Close()
 92
 93	honkids := make(map[int64]bool)
 94	for c := range convoys {
 95		rows = qordie(orig, "select honkid, userid, what, honker, xid, rid, dt, url, audience, noise, convoy, whofore, format, precis, oonker, flags, plain from honks where convoy = ?", c)
 96		for rows.Next() {
 97			var honkid, userid int64
 98			var what, honker, xid, rid, dt, url, audience, noise, convoy, plain string
 99			var whofore int64
100			var format, precis, oonker string
101			var flags int64
102			scanordie(rows, &honkid, &userid, &what, &honker, &xid, &rid, &dt, &url, &audience, &noise, &convoy, &whofore, &format, &precis, &oonker, &flags, &plain)
103			honkids[honkid] = true
104			doordie(tx, "insert into honks (honkid, userid, what, honker, xid, rid, dt, url, audience, noise, convoy, whofore, format, precis, oonker, flags, plain) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", honkid, userid, what, honker, xid, rid, dt, url, audience, noise, convoy, whofore, format, precis, oonker, flags, plain)
105		}
106		rows.Close()
107	}
108	fileids := make(map[int64]bool)
109	for h := range honkids {
110		rows = qordie(orig, "select honkid, chonkid, fileid from donks where honkid = ?", h)
111		for rows.Next() {
112			var honkid, chonkid, fileid int64
113			scanordie(rows, &honkid, &chonkid, &fileid)
114			fileids[fileid] = true
115			doordie(tx, "insert into donks (honkid, chonkid, fileid) values (?, ?, ?)", honkid, chonkid, fileid)
116		}
117		rows.Close()
118		rows = qordie(orig, "select ontology, honkid from onts where honkid = ?", h)
119		for rows.Next() {
120			var ontology string
121			var honkid int64
122			scanordie(rows, &ontology, &honkid)
123			doordie(tx, "insert into onts (ontology, honkid) values (?, ?)", ontology, honkid)
124		}
125		rows.Close()
126		rows = qordie(orig, "select honkid, genus, json from honkmeta where honkid = ?", h)
127		for rows.Next() {
128			var honkid int64
129			var genus, json string
130			scanordie(rows, &honkid, &genus, &json)
131			doordie(tx, "insert into honkmeta (honkid, genus, json) values (?, ?, ?)", honkid, genus, json)
132		}
133		rows.Close()
134	}
135	chonkids := make(map[int64]bool)
136	rows = qordie(orig, "select chonkid, userid, xid, who, target, dt, noise, format from chonks")
137	for rows.Next() {
138		var chonkid, userid int64
139		var xid, who, target, dt, noise, format string
140		scanordie(rows, &chonkid, &userid, &xid, &who, &target, &dt, &noise, &format)
141		chonkids[chonkid] = true
142		doordie(tx, "insert into chonks (chonkid, userid, xid, who, target, dt, noise, format) values (?, ?, ?, ?, ?, ?, ?, ?)", chonkid, userid, xid, who, target, dt, noise, format)
143	}
144	rows.Close()
145	for c := range chonkids {
146		rows = qordie(orig, "select honkid, chonkid, fileid from donks where chonkid = ?", c)
147		for rows.Next() {
148			var honkid, chonkid, fileid int64
149			scanordie(rows, &honkid, &chonkid, &fileid)
150			fileids[fileid] = true
151			doordie(tx, "insert into donks (honkid, chonkid, fileid) values (?, ?, ?)", honkid, chonkid, fileid)
152		}
153		rows.Close()
154	}
155	filexids := make(map[string]bool)
156	for f := range fileids {
157		rows = qordie(orig, "select fileid, xid, name, description, url, media, local from filemeta where fileid = ?", f)
158		for rows.Next() {
159			var fileid int64
160			var xid, name, description, url, media string
161			var local int64
162			scanordie(rows, &fileid, &xid, &name, &description, &url, &media, &local)
163			filexids[xid] = true
164			doordie(tx, "insert into filemeta (fileid, xid, name, description, url, media, local) values (?, ?, ?, ?, ?, ?, ?)", fileid, xid, name, description, url, media, local)
165		}
166		rows.Close()
167	}
168
169	rows = qordie(orig, "select key, value from config")
170	for rows.Next() {
171		var key string
172		var value interface{}
173		scanordie(rows, &key, &value)
174		doordie(tx, "insert into config (key, value) values (?, ?)", key, value)
175	}
176
177	err = tx.Commit()
178	if err != nil {
179		elog.Fatalf("can't commit backp: %s", err)
180	}
181	backup.Close()
182
183	backupblobname := fmt.Sprintf("%s/blob-%d.db", dirname, now)
184	blob, err := sql.Open("sqlite3", backupblobname)
185	if err != nil {
186		elog.Fatalf("can't open backup blob database")
187	}
188	_, err = blob.Exec("PRAGMA journal_mode=WAL")
189	doordie(blob, "create table filedata (xid text, media text, hash text, content blob)")
190	doordie(blob, "create index idx_filexid on filedata(xid)")
191	doordie(blob, "create index idx_filehash on filedata(hash)")
192	tx, err = blob.Begin()
193	if err != nil {
194		elog.Fatalf("can't start transaction: %s", err)
195	}
196	origblob := openblobdb()
197	for x := range filexids {
198		rows = qordie(origblob, "select xid, media, hash, content from filedata where xid = ?", x)
199		for rows.Next() {
200			var xid, media, hash string
201			var content sql.RawBytes
202			scanordie(rows, &xid, &media, &hash, &content)
203			doordie(tx, "insert into filedata (xid, media, hash, content) values (?, ?, ?, ?)", xid, media, hash, content)
204		}
205		rows.Close()
206	}
207
208	err = tx.Commit()
209	if err != nil {
210		elog.Fatalf("can't commit blobs: %s", err)
211	}
212	blob.Close()
213}