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