dataStore_bolt.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  1. // +build !BADGER_DB,!FILES_DB
  2. /*
  3. * Copyright (c) 2018, Psiphon Inc.
  4. * All rights reserved.
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. *
  19. */
  20. package psiphon
  21. import (
  22. std_errors "errors"
  23. "os"
  24. "path/filepath"
  25. "runtime/debug"
  26. "sync/atomic"
  27. "time"
  28. "github.com/Psiphon-Labs/bolt"
  29. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/errors"
  30. )
  31. type datastoreDB struct {
  32. boltDB *bolt.DB
  33. isFailed int32
  34. }
  35. type datastoreTx struct {
  36. db *datastoreDB
  37. boltTx *bolt.Tx
  38. }
  39. type datastoreBucket struct {
  40. db *datastoreDB
  41. boltBucket *bolt.Bucket
  42. }
  43. type datastoreCursor struct {
  44. db *datastoreDB
  45. boltCursor *bolt.Cursor
  46. }
  47. func datastoreOpenDB(rootDataDirectory string) (*datastoreDB, error) {
  48. var db *datastoreDB
  49. var err error
  50. for retry := 0; retry < 3; retry++ {
  51. db, err = tryDatastoreOpenDB(rootDataDirectory, retry > 0)
  52. if err == nil {
  53. break
  54. }
  55. NoticeWarning("tryDatastoreOpenDB failed: %s", err)
  56. // The datastore file may be corrupt, so, in subsequent iterations, set the
  57. // "reset" flag and attempt to delete the file and try again.
  58. }
  59. return db, err
  60. }
  61. func tryDatastoreOpenDB(rootDataDirectory string, reset bool) (retdb *datastoreDB, reterr error) {
  62. // Testing indicates that the bolt Check function can raise SIGSEGV due to
  63. // invalid mmap buffer accesses in cases such as opening a valid but
  64. // truncated datastore file.
  65. //
  66. // To handle this, we temporarily set SetPanicOnFault in order to treat the
  67. // fault as a panic, recover any panic, and return an error which will result
  68. // in a retry with reset.
  69. // Begin recovery preamble
  70. panicOnFault := debug.SetPanicOnFault(true)
  71. defer debug.SetPanicOnFault(panicOnFault)
  72. defer func() {
  73. if r := recover(); r != nil {
  74. retdb = nil
  75. reterr = errors.Tracef("panic: %v", r)
  76. }
  77. }()
  78. // End recovery preamble
  79. filename := filepath.Join(rootDataDirectory, "psiphon.boltdb")
  80. if reset {
  81. NoticeWarning("tryDatastoreOpenDB: reset")
  82. os.Remove(filename)
  83. }
  84. newDB, err := bolt.Open(filename, 0600, &bolt.Options{Timeout: 1 * time.Second})
  85. if err != nil {
  86. return nil, errors.Trace(err)
  87. }
  88. // Run consistency checks on datastore and emit errors for diagnostics
  89. // purposes. We assume this will complete quickly for typical size Psiphon
  90. // datastores and wait for the check to complete before proceeding.
  91. err = newDB.View(func(tx *bolt.Tx) error {
  92. return tx.SynchronousCheck()
  93. })
  94. if err != nil {
  95. return nil, errors.Trace(err)
  96. }
  97. err = newDB.Update(func(tx *bolt.Tx) error {
  98. requiredBuckets := [][]byte{
  99. datastoreServerEntriesBucket,
  100. datastoreServerEntryTagsBucket,
  101. datastoreServerEntryTombstoneTagsBucket,
  102. datastoreSplitTunnelRouteETagsBucket,
  103. datastoreSplitTunnelRouteDataBucket,
  104. datastoreUrlETagsBucket,
  105. datastoreKeyValueBucket,
  106. datastoreRemoteServerListStatsBucket,
  107. datastoreFailedTunnelStatsBucket,
  108. datastoreSLOKsBucket,
  109. datastoreTacticsBucket,
  110. datastoreSpeedTestSamplesBucket,
  111. datastoreDialParametersBucket,
  112. }
  113. for _, bucket := range requiredBuckets {
  114. _, err := tx.CreateBucketIfNotExists(bucket)
  115. if err != nil {
  116. return err
  117. }
  118. }
  119. return nil
  120. })
  121. if err != nil {
  122. return nil, errors.Trace(err)
  123. }
  124. // Cleanup obsolete buckets
  125. err = newDB.Update(func(tx *bolt.Tx) error {
  126. obsoleteBuckets := [][]byte{
  127. []byte("tunnelStats"),
  128. []byte("rankedServerEntries"),
  129. }
  130. for _, obsoleteBucket := range obsoleteBuckets {
  131. if tx.Bucket(obsoleteBucket) != nil {
  132. err := tx.DeleteBucket(obsoleteBucket)
  133. if err != nil {
  134. NoticeWarning("DeleteBucket %s error: %s", obsoleteBucket, err)
  135. // Continue, since this is not fatal
  136. }
  137. }
  138. }
  139. return nil
  140. })
  141. if err != nil {
  142. return nil, errors.Trace(err)
  143. }
  144. return &datastoreDB{boltDB: newDB}, nil
  145. }
  146. var errDatastoreFailed = std_errors.New("datastore has failed")
  147. func (db *datastoreDB) isDatastoreFailed() bool {
  148. return atomic.LoadInt32(&db.isFailed) == 1
  149. }
  150. func (db *datastoreDB) setDatastoreFailed(r interface{}) {
  151. atomic.StoreInt32(&db.isFailed, 1)
  152. NoticeWarning("Datastore failed: %s", errors.Tracef("panic: %v", r))
  153. }
  154. func (db *datastoreDB) close() error {
  155. // Limitation: there is no panic recover in this case. We assume boltDB.Close
  156. // does not make mmap accesses and prefer to not continue with the datastore
  157. // file in a locked or open state. We also assume that any locks aquired by
  158. // boltDB.Close, held by transactions, will be released even if the
  159. // transaction panics and the database is in the failed state.
  160. return db.boltDB.Close()
  161. }
  162. func (db *datastoreDB) view(fn func(tx *datastoreTx) error) (reterr error) {
  163. // Any bolt function that performs mmap buffer accesses can raise SIGBUS due
  164. // to underlying storage changes, such as a truncation of the datastore file
  165. // or removal or network attached storage, etc.
  166. //
  167. // To handle this, we temporarily set SetPanicOnFault in order to treat the
  168. // fault as a panic, recover any panic to avoid crashing the process, and
  169. // putting this datastoreDB instance into a failed state. All subsequent
  170. // calls to this datastoreDBinstance or its related datastoreTx and
  171. // datastoreBucket instances will fail.
  172. // Begin recovery preamble
  173. if db.isDatastoreFailed() {
  174. return errDatastoreFailed
  175. }
  176. panicOnFault := debug.SetPanicOnFault(true)
  177. defer debug.SetPanicOnFault(panicOnFault)
  178. defer func() {
  179. if r := recover(); r != nil {
  180. db.setDatastoreFailed(r)
  181. reterr = errDatastoreFailed
  182. }
  183. }()
  184. // End recovery preamble
  185. return db.boltDB.View(
  186. func(tx *bolt.Tx) error {
  187. err := fn(&datastoreTx{db: db, boltTx: tx})
  188. if err != nil {
  189. return errors.Trace(err)
  190. }
  191. return nil
  192. })
  193. }
  194. func (db *datastoreDB) update(fn func(tx *datastoreTx) error) (reterr error) {
  195. // Begin recovery preamble
  196. if db.isDatastoreFailed() {
  197. return errDatastoreFailed
  198. }
  199. panicOnFault := debug.SetPanicOnFault(true)
  200. defer debug.SetPanicOnFault(panicOnFault)
  201. defer func() {
  202. if r := recover(); r != nil {
  203. db.setDatastoreFailed(r)
  204. reterr = errDatastoreFailed
  205. }
  206. }()
  207. // End recovery preamble
  208. return db.boltDB.Update(
  209. func(tx *bolt.Tx) error {
  210. err := fn(&datastoreTx{db: db, boltTx: tx})
  211. if err != nil {
  212. return errors.Trace(err)
  213. }
  214. return nil
  215. })
  216. }
  217. func (tx *datastoreTx) bucket(name []byte) (retbucket *datastoreBucket) {
  218. // Begin recovery preamble
  219. if tx.db.isDatastoreFailed() {
  220. return &datastoreBucket{db: tx.db, boltBucket: nil}
  221. }
  222. panicOnFault := debug.SetPanicOnFault(true)
  223. defer debug.SetPanicOnFault(panicOnFault)
  224. defer func() {
  225. if r := recover(); r != nil {
  226. tx.db.setDatastoreFailed(r)
  227. retbucket = &datastoreBucket{db: tx.db, boltBucket: nil}
  228. }
  229. }()
  230. // End recovery preamble
  231. return &datastoreBucket{db: tx.db, boltBucket: tx.boltTx.Bucket(name)}
  232. }
  233. func (tx *datastoreTx) clearBucket(name []byte) (reterr error) {
  234. // Begin recovery preamble
  235. if tx.db.isDatastoreFailed() {
  236. return errDatastoreFailed
  237. }
  238. panicOnFault := debug.SetPanicOnFault(true)
  239. defer debug.SetPanicOnFault(panicOnFault)
  240. defer func() {
  241. if r := recover(); r != nil {
  242. tx.db.setDatastoreFailed(r)
  243. reterr = errDatastoreFailed
  244. }
  245. }()
  246. // End recovery preamble
  247. err := tx.boltTx.DeleteBucket(name)
  248. if err != nil {
  249. return errors.Trace(err)
  250. }
  251. _, err = tx.boltTx.CreateBucket(name)
  252. if err != nil {
  253. return errors.Trace(err)
  254. }
  255. return nil
  256. }
  257. func (b *datastoreBucket) get(key []byte) (retvalue []byte) {
  258. // Begin recovery preamble
  259. if b.db.isDatastoreFailed() {
  260. return nil
  261. }
  262. panicOnFault := debug.SetPanicOnFault(true)
  263. defer debug.SetPanicOnFault(panicOnFault)
  264. defer func() {
  265. if r := recover(); r != nil {
  266. b.db.setDatastoreFailed(r)
  267. retvalue = nil
  268. }
  269. }()
  270. // End recovery preamble
  271. return b.boltBucket.Get(key)
  272. }
  273. func (b *datastoreBucket) put(key, value []byte) (reterr error) {
  274. // Begin recovery preamble
  275. if b.db.isDatastoreFailed() {
  276. return errDatastoreFailed
  277. }
  278. panicOnFault := debug.SetPanicOnFault(true)
  279. defer debug.SetPanicOnFault(panicOnFault)
  280. defer func() {
  281. if r := recover(); r != nil {
  282. b.db.setDatastoreFailed(r)
  283. reterr = errDatastoreFailed
  284. }
  285. }()
  286. // End recovery preamble
  287. err := b.boltBucket.Put(key, value)
  288. if err != nil {
  289. return errors.Trace(err)
  290. }
  291. return nil
  292. }
  293. func (b *datastoreBucket) delete(key []byte) (reterr error) {
  294. // Begin recovery preamble
  295. if b.db.isDatastoreFailed() {
  296. return errDatastoreFailed
  297. }
  298. panicOnFault := debug.SetPanicOnFault(true)
  299. defer debug.SetPanicOnFault(panicOnFault)
  300. defer func() {
  301. if r := recover(); r != nil {
  302. b.db.setDatastoreFailed(r)
  303. reterr = errDatastoreFailed
  304. }
  305. }()
  306. // End recovery preamble
  307. err := b.boltBucket.Delete(key)
  308. if err != nil {
  309. return errors.Trace(err)
  310. }
  311. return nil
  312. }
  313. func (b *datastoreBucket) cursor() (retcursor datastoreCursor) {
  314. // Begin recovery preamble
  315. if b.db.isDatastoreFailed() {
  316. return datastoreCursor{db: b.db, boltCursor: nil}
  317. }
  318. panicOnFault := debug.SetPanicOnFault(true)
  319. defer debug.SetPanicOnFault(panicOnFault)
  320. defer func() {
  321. if r := recover(); r != nil {
  322. b.db.setDatastoreFailed(r)
  323. retcursor = datastoreCursor{db: b.db, boltCursor: nil}
  324. }
  325. }()
  326. // End recovery preamble
  327. return datastoreCursor{db: b.db, boltCursor: b.boltBucket.Cursor()}
  328. }
  329. func (c *datastoreCursor) firstKey() (retkey []byte) {
  330. // Begin recovery preamble
  331. if c.db.isDatastoreFailed() {
  332. return nil
  333. }
  334. panicOnFault := debug.SetPanicOnFault(true)
  335. defer debug.SetPanicOnFault(panicOnFault)
  336. defer func() {
  337. if r := recover(); r != nil {
  338. c.db.setDatastoreFailed(r)
  339. retkey = nil
  340. }
  341. }()
  342. // End recovery preamble
  343. key, _ := c.boltCursor.First()
  344. return key
  345. }
  346. func (c *datastoreCursor) nextKey() (retkey []byte) {
  347. // Begin recovery preamble
  348. if c.db.isDatastoreFailed() {
  349. return nil
  350. }
  351. panicOnFault := debug.SetPanicOnFault(true)
  352. defer debug.SetPanicOnFault(panicOnFault)
  353. defer func() {
  354. if r := recover(); r != nil {
  355. c.db.setDatastoreFailed(r)
  356. retkey = nil
  357. }
  358. }()
  359. // End recovery preamble
  360. key, _ := c.boltCursor.Next()
  361. return key
  362. }
  363. func (c *datastoreCursor) first() (retkey, retvalue []byte) {
  364. // Begin recovery preamble
  365. if c.db.isDatastoreFailed() {
  366. return nil, nil
  367. }
  368. panicOnFault := debug.SetPanicOnFault(true)
  369. defer debug.SetPanicOnFault(panicOnFault)
  370. defer func() {
  371. if r := recover(); r != nil {
  372. c.db.setDatastoreFailed(r)
  373. retkey = nil
  374. retvalue = nil
  375. }
  376. }()
  377. // End recovery preamble
  378. return c.boltCursor.First()
  379. }
  380. func (c *datastoreCursor) next() (retkey, retvalue []byte) {
  381. // Begin recovery preamble
  382. if c.db.isDatastoreFailed() {
  383. return nil, nil
  384. }
  385. panicOnFault := debug.SetPanicOnFault(true)
  386. defer debug.SetPanicOnFault(panicOnFault)
  387. defer func() {
  388. if r := recover(); r != nil {
  389. c.db.setDatastoreFailed(r)
  390. retkey = nil
  391. retvalue = nil
  392. }
  393. }()
  394. // End recovery preamble
  395. return c.boltCursor.Next()
  396. }
  397. func (c *datastoreCursor) close() {
  398. // BoltDB doesn't close cursors.
  399. }