backupdb.go (view raw)
1package main
2
3import (
4 "database/sql"
5 "fmt"
6 "log"
7 "os"
8 "time"
9
10 "strings"
11)
12
13func qordie(db *sql.DB, s string, args ...interface{}) *sql.Rows {
14 rows, err := db.Query(s, args...)
15 if err != nil {
16 log.Fatalf("can't query %s: %s", s, err)
17 }
18 return rows
19}
20
21func scanordie(rows *sql.Rows, args ...interface{}) {
22 err := rows.Scan(args...)
23 if err != nil {
24 log.Fatalf("can't scan: %s", err)
25 }
26}
27
28func svalbard(dirname string) {
29 err := os.Mkdir(dirname, 0700)
30 if err != nil && !os.IsExist(err) {
31 log.Fatalf("can't create directory: %s", dirname)
32 }
33 now := time.Now().Unix()
34 backupdbname := fmt.Sprintf("%s/honk-%d.db", dirname, now)
35 backup, err := sql.Open("sqlite3", backupdbname)
36 if err != nil {
37 log.Fatalf("can't open backup database")
38 }
39 for _, line := range strings.Split(sqlSchema, ";") {
40 _, err = backup.Exec(line)
41 if err != nil {
42 log.Fatal(err)
43 return
44 }
45 }
46 tx, err := backup.Begin()
47 if err != nil {
48 log.Fatal(err)
49 }
50 orig := opendatabase()
51 rows := qordie(orig, "select userid, username, hash, displayname, about, pubkey, seckey, options from users")
52 for rows.Next() {
53 var userid int64
54 var username, hash, displayname, about, pubkey, seckey, options string
55 scanordie(rows, &userid, &username, &hash, &displayname, &about, &pubkey, &seckey, &options)
56 doordie(tx, "insert into users (userid, username, hash, displayname, about, pubkey, seckey, options) values (?, ?, ?, ?, ?, ?, ?, ?)", userid, username, hash, displayname, about, pubkey, seckey, options)
57 }
58 rows.Close()
59
60 rows = qordie(orig, "select honkerid, userid, name, xid, flavor, combos, owner, meta, folxid from honkers")
61 for rows.Next() {
62 var honkerid, userid int64
63 var name, xid, flavor, combos, owner, meta, folxid string
64 scanordie(rows, &honkerid, &userid, &name, &xid, &flavor, &combos, &owner, &meta, &folxid)
65 doordie(tx, "insert into honkers (honkerid, userid, name, xid, flavor, combos, owner, meta, folxid) values (?, ?, ?, ?, ?, ?, ?, ?, ?)", honkerid, userid, name, xid, flavor, combos, owner, meta, folxid)
66 }
67 rows.Close()
68
69 rows = qordie(orig, "select convoy from honks where flags & 4 or whofore = 2 or whofore = 3")
70 convoys := make(map[string]bool)
71 for rows.Next() {
72 var convoy string
73 scanordie(rows, &convoy)
74 convoys[convoy] = true
75 }
76 rows.Close()
77
78 honkids := make(map[int64]bool)
79 for c := range convoys {
80 rows = qordie(orig, "select honkid, userid, what, honker, xid, rid, dt, url, audience, noise, convoy, whofore, format, precis, oonker, flags from honks where convoy = ?", c)
81 for rows.Next() {
82 var honkid, userid int64
83 var what, honker, xid, rid, dt, url, audience, noise, convoy string
84 var whofore int64
85 var format, precis, oonker string
86 var flags int64
87 scanordie(rows, &honkid, &userid, &what, &honker, &xid, &rid, &dt, &url, &audience, &noise, &convoy, &whofore, &format, &precis, &oonker, &flags)
88 honkids[honkid] = true
89 doordie(tx, "insert into honks (honkid, userid, what, honker, xid, rid, dt, url, audience, noise, convoy, whofore, format, precis, oonker, flags) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", honkid, userid, what, honker, xid, rid, dt, url, audience, noise, convoy, whofore, format, precis, oonker, flags)
90 }
91 rows.Close()
92 }
93 fileids := make(map[int64]bool)
94 for h := range honkids {
95 rows = qordie(orig, "select honkid, chonkid, fileid from donks where honkid = ?", h)
96 for rows.Next() {
97 var honkid, chonkid, fileid int64
98 scanordie(rows, &honkid, &chonkid, &fileid)
99 fileids[fileid] = true
100 doordie(tx, "insert into donks (honkid, chonkid, fileid) values (?, ?, ?)", honkid, chonkid, fileid)
101 }
102 rows.Close()
103 rows = qordie(orig, "select ontology, honkid from onts where honkid = ?", h)
104 for rows.Next() {
105 var ontology string
106 var honkid int64
107 scanordie(rows, &ontology, &honkid)
108 doordie(tx, "insert into onts (ontology, honkid) values (?, ?)", ontology, honkid)
109 }
110 rows.Close()
111 rows = qordie(orig, "select honkid, genus, json from honkmeta where honkid = ?", h)
112 for rows.Next() {
113 var honkid int64
114 var genus, json string
115 scanordie(rows, &honkid, &genus, &json)
116 doordie(tx, "insert into honkmeta (honkid, genus, json) values (?, ?, ?)", honkid, genus, json)
117 }
118 rows.Close()
119 }
120 chonkids := make(map[int64]bool)
121 rows = qordie(orig, "select chonkid, userid, xid, who, target, dt, noise, format from chonks")
122 for rows.Next() {
123 var chonkid, userid int64
124 var xid, who, target, dt, noise, format string
125 scanordie(rows, &chonkid, &userid, &xid, &who, &target, &dt, &noise, &format)
126 chonkids[chonkid] = true
127 doordie(tx, "insert into chonks (chonkid, userid, xid, who, target, dt, noise, format) values (?, ?, ?, ?, ?, ?, ?, ?)", chonkid, userid, xid, who, target, dt, noise, format)
128 }
129 rows.Close()
130 for c := range chonkids {
131 rows = qordie(orig, "select honkid, chonkid, fileid from donks where chonkid = ?", c)
132 for rows.Next() {
133 var honkid, chonkid, fileid int64
134 scanordie(rows, &honkid, &chonkid, &fileid)
135 fileids[fileid] = true
136 doordie(tx, "insert into donks (honkid, chonkid, fileid) values (?, ?, ?)", honkid, chonkid, fileid)
137 }
138 rows.Close()
139 }
140 filexids := make(map[string]bool)
141 for f := range fileids {
142 rows = qordie(orig, "select fileid, xid, name, description, url, media, local from filemeta where fileid = ?", f)
143 for rows.Next() {
144 var fileid int64
145 var xid, name, description, url, media string
146 var local int64
147 scanordie(rows, &fileid, &xid, &name, &description, &url, &media, &local)
148 filexids[xid] = true
149 doordie(tx, "insert into filemeta (fileid, xid, name, description, url, media, local) values (?, ?, ?, ?, ?, ?, ?)", fileid, xid, name, description, url, media, local)
150 }
151 rows.Close()
152 }
153
154 rows = qordie(orig, "select key, value from config")
155 for rows.Next() {
156 var key string
157 var value interface{}
158 scanordie(rows, &key, &value)
159 doordie(tx, "insert into config (key, value) values (?, ?)", key, value)
160 }
161
162 err = tx.Commit()
163 if err != nil {
164 log.Fatalf("can't commit backp: %s", err)
165 }
166 backup.Close()
167
168 backupblobname := fmt.Sprintf("%s/blob-%d.db", dirname, now)
169 blob, err := sql.Open("sqlite3", backupblobname)
170 if err != nil {
171 log.Fatalf("can't open backup blob database")
172 }
173 doordie(blob, "create table filedata (xid text, media text, hash text, content blob)")
174 doordie(blob, "create index idx_filexid on filedata(xid)")
175 doordie(blob, "create index idx_filehash on filedata(hash)")
176 tx, err = blob.Begin()
177 if err != nil {
178 log.Fatalf("can't start transaction: %s", err)
179 }
180 origblob := openblobdb()
181 for x := range filexids {
182 rows = qordie(origblob, "select xid, media, hash, content from filedata where xid = ?", x)
183 for rows.Next() {
184 var xid, media, hash string
185 var content sql.RawBytes
186 scanordie(rows, &xid, &media, &hash, &content)
187 doordie(tx, "insert into filedata (xid, media, hash, content) values (?, ?, ?)", xid, media, hash, content)
188 }
189 rows.Close()
190 }
191
192 err = tx.Commit()
193 if err != nil {
194 log.Fatalf("can't commit blobs: %s", err)
195 }
196 blob.Close()
197}