dataStore_bolt.go 11 KB

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