No Description

db.go 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550
  1. package funmow
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. "encoding/json"
  6. "errors"
  7. "fmt"
  8. "github.com/boltdb/bolt"
  9. "strconv"
  10. )
  11. const (
  12. DEBUG = false
  13. )
  14. type DBRef int
  15. func NewDBRefFromHashRef(v string) (DBRef, error) {
  16. var destInt int
  17. n, err := fmt.Sscanf(v, "#%d", &destInt)
  18. if err != nil || n == 0 {
  19. return 0, err
  20. }
  21. return DBRef(destInt), nil
  22. }
  23. func NewDBRefFromString(v string) (DBRef, error) {
  24. intVal, err := strconv.Atoi(v)
  25. return DBRef(intVal), err
  26. }
  27. func NewDBRefFromKey(b []byte) DBRef {
  28. return DBRef(binary.BigEndian.Uint64(b))
  29. }
  30. func NewDBRefFromChildKey(b []byte) DBRef { // returns the child part of a childkey
  31. return DBRef(binary.BigEndian.Uint64(b[8:]))
  32. }
  33. func (r DBRef) Valid() bool {
  34. return r != 0
  35. }
  36. func (r DBRef) Limbo() bool {
  37. return r == 0
  38. }
  39. func (r DBRef) String() string {
  40. return strconv.Itoa(int(r))
  41. }
  42. func (r DBRef) Key() []byte {
  43. b := make([]byte, 8)
  44. binary.BigEndian.PutUint64(b, uint64(r))
  45. return b
  46. }
  47. func (r DBRef) ChildKey(s DBRef) []byte {
  48. b := make([]byte, 16)
  49. binary.BigEndian.PutUint64(b, uint64(r))
  50. binary.BigEndian.PutUint64(b[8:], uint64(s))
  51. return b
  52. }
  53. type DBRefList []DBRef
  54. func (l DBRefList) First() DBRef {
  55. if len(l) > 0 {
  56. return l[0]
  57. } else {
  58. return 0
  59. }
  60. }
  61. type DB struct {
  62. path string
  63. db *bolt.DB
  64. }
  65. func NewDB(path string) *DB {
  66. return &DB{path: path}
  67. }
  68. func (s *DB) Close() {
  69. s.db.Close()
  70. }
  71. func (s *DB) Open() error {
  72. var err error
  73. s.db, err = bolt.Open(s.path, 0600, nil)
  74. if err != nil {
  75. return err
  76. }
  77. return s.db.Update(func(tx *bolt.Tx) error {
  78. var err error
  79. objectBucket, err := tx.CreateBucketIfNotExists([]byte("object"))
  80. if err != nil {
  81. return fmt.Errorf("create bucket: %s", err)
  82. }
  83. _, err = tx.CreateBucketIfNotExists([]byte("child"))
  84. if err != nil {
  85. return fmt.Errorf("create bucket: %s", err)
  86. }
  87. _, err = tx.CreateBucketIfNotExists([]byte("parent"))
  88. if err != nil {
  89. return fmt.Errorf("create bucket: %s", err)
  90. }
  91. _, err = tx.CreateBucketIfNotExists([]byte("player"))
  92. if err != nil {
  93. return fmt.Errorf("create bucket: %s", err)
  94. }
  95. // make sure we have a limbo
  96. if _, found := s.txRetrieveObject(objectBucket, 0); !found {
  97. limbo := Object{Name: "Limbo", Description: "There's very little to see here.", ID: 0}
  98. err = s.txStoreObject(objectBucket, limbo, 0)
  99. if err != nil {
  100. return err
  101. }
  102. }
  103. return nil
  104. })
  105. }
  106. func (s *DB) Allocate() (DBRef, error) {
  107. var id DBRef
  108. err := s.db.Update(func(tx *bolt.Tx) error {
  109. b := tx.Bucket([]byte("object"))
  110. seq, err := b.NextSequence()
  111. if err != nil {
  112. return err
  113. }
  114. id = DBRef(seq)
  115. return s.txStoreObject(b, Object{ID: id}, id)
  116. })
  117. return id, err
  118. }
  119. func (s *DB) Fetch(r DBRef) (Object, bool) { // this has become simply an alias for RetrieveObject
  120. return s.RetrieveObject(r)
  121. }
  122. func (s *DB) DumpObject(r DBRef) string {
  123. var dump string
  124. s.db.View(func(tx *bolt.Tx) error {
  125. objectBucket := tx.Bucket([]byte("object"))
  126. childBucket := tx.Bucket([]byte("child"))
  127. parentBucket := tx.Bucket([]byte("parent"))
  128. objectDump := string(objectBucket.Get(r.Key()))
  129. intermediate := make([]string, 0)
  130. children := s.txGetChildren(childBucket, r)
  131. for childID, childType := range children {
  132. intermediate = append(intermediate, fmt.Sprintf("#%d (%s)", childID, childType))
  133. }
  134. parent, hasParent := s.txGetParent(parentBucket, r)
  135. dump = fmt.Sprintf("Object: %s\nHas Parent: %t\nParent ID: #%d\nChildren: %s", objectDump, hasParent, parent, intermediate)
  136. return nil
  137. })
  138. return dump
  139. }
  140. func (s *DB) Delete(objectID DBRef) error {
  141. return s.db.Update(func(tx *bolt.Tx) error {
  142. objectBucket := tx.Bucket([]byte("object"))
  143. childBucket := tx.Bucket([]byte("child"))
  144. parentBucket := tx.Bucket([]byte("parent"))
  145. _, found := s.txRetrieveObject(objectBucket, objectID)
  146. if !found {
  147. return nil
  148. }
  149. parentID, parentFound := s.txGetParent(parentBucket, objectID)
  150. if parentFound {
  151. //fmt.Printf("Unlinking from parent #%d\n", parentID)
  152. err := s.txUnlink(childBucket, parentBucket, parentID, objectID)
  153. if err != nil {
  154. return err
  155. }
  156. }
  157. children := s.txGetChildren(childBucket, objectID)
  158. for childID, childType := range children {
  159. //fmt.Printf("Unlinking child #%d\n",childID)
  160. err := s.txUnlink(childBucket, parentBucket, objectID, childID)
  161. if err != nil {
  162. return err
  163. }
  164. if childType == "exit" {
  165. //fmt.Printf("Deleting exit child #%d\n", childID)
  166. err := s.txDelete(objectBucket, childID) // this is bad and will create orphans
  167. if err != nil {
  168. return err
  169. }
  170. } else {
  171. // even if parentfound == false, parentID will = 0 (the default value for rooms)
  172. // that will cause the contents of destroyed rooms to end up in limbo, instead of as orpans
  173. //fmt.Printf("Linking child #%d to parent #%d\n",childID, parentID)
  174. err := s.txLink(childBucket, parentBucket, parentID, childID, childType)
  175. if err != nil {
  176. return err
  177. }
  178. }
  179. }
  180. //fmt.Printf("Deleting object #%d\n", objectID)
  181. err := s.txDelete(objectBucket, objectID)
  182. if err != nil {
  183. return err
  184. }
  185. if DEBUG {
  186. fmt.Printf("Delete name: id: %d\n", objectID)
  187. }
  188. return nil
  189. })
  190. }
  191. func (s *DB) SetPlayerID(name string, id DBRef) error {
  192. err := s.db.Update(func(tx *bolt.Tx) error {
  193. b := tx.Bucket([]byte("player"))
  194. if b == nil {
  195. return errors.New("Player bucket not found")
  196. }
  197. return b.Put([]byte(name), id.Key())
  198. })
  199. if DEBUG {
  200. fmt.Printf("SetPlayerID name: %s id: %d\n", name, id)
  201. }
  202. return err
  203. }
  204. func (s *DB) GetPlayerID(name string) (DBRef, error) {
  205. var id DBRef
  206. err := s.db.View(func(tx *bolt.Tx) error {
  207. b := tx.Bucket([]byte("player"))
  208. if b == nil {
  209. return errors.New("Player bucket not found")
  210. }
  211. v := b.Get([]byte(name))
  212. if v == nil {
  213. return errors.New("Player not found")
  214. }
  215. id = NewDBRefFromKey(v)
  216. return nil
  217. })
  218. if DEBUG {
  219. fmt.Printf("GetPlayerID name: %s id: %d\n", name, id)
  220. }
  221. return id, err
  222. }
  223. func (s *DB) CreatePlayer(name string) (DBRef, error) {
  224. var playerID DBRef
  225. err := s.db.Update(func(tx *bolt.Tx) error {
  226. objectBucket := tx.Bucket([]byte("object"))
  227. playerBucket := tx.Bucket([]byte("player"))
  228. seq, err := objectBucket.NextSequence()
  229. if err != nil {
  230. return err
  231. }
  232. playerID = DBRef(seq)
  233. s.txStoreObject(objectBucket, Object{ID: playerID, Name: name, Type: "player"}, playerID)
  234. err = playerBucket.Put([]byte(name), playerID.Key())
  235. return err
  236. })
  237. if DEBUG {
  238. fmt.Printf("CreatePlayer name: %s id: %d\n", name, playerID)
  239. }
  240. return playerID, err
  241. }
  242. // All of these functions exist in two forms; one for use inside a transaction and one
  243. // for use outside a transaction.
  244. func (s *DB) RetrieveObject(id DBRef) (Object, bool) {
  245. o := Object{}
  246. f := false
  247. s.db.View(func(tx *bolt.Tx) error {
  248. b := tx.Bucket([]byte("object"))
  249. o, f = s.txRetrieveObject(b, id)
  250. return nil
  251. })
  252. return o, f
  253. }
  254. func (s *DB) txRetrieveObject(b *bolt.Bucket, id DBRef) (Object, bool) {
  255. o := Object{}
  256. f := false
  257. v := b.Get(id.Key())
  258. if v != nil {
  259. err := json.Unmarshal(v, &o)
  260. if err == nil {
  261. f = true
  262. if DEBUG {
  263. fmt.Printf("txRetrieveObject id: %d\n", id)
  264. }
  265. }
  266. }
  267. o.db = s // bit ugly but saves a lot of headaches
  268. return o, f
  269. }
  270. func (s *DB) StoreObject(o Object, id DBRef) error {
  271. return s.db.Update(func(tx *bolt.Tx) error {
  272. b := tx.Bucket([]byte("object"))
  273. return s.txStoreObject(b, o, id)
  274. })
  275. }
  276. func (s *DB) txStoreObject(b *bolt.Bucket, o Object, id DBRef) error {
  277. buf, err := json.Marshal(o)
  278. //fmt.Println("txStoreObject", id.String(), string(buf))
  279. if err != nil {
  280. return err
  281. }
  282. err = b.Put(id.Key(), buf)
  283. if err != nil {
  284. return err
  285. }
  286. if DEBUG {
  287. fmt.Printf("txStoreObject id: %d\n", id)
  288. }
  289. return nil
  290. }
  291. func (s *DB) GetChildren(src DBRef) map[DBRef]string {
  292. var l map[DBRef]string
  293. s.db.View(func(tx *bolt.Tx) error {
  294. c := tx.Bucket([]byte("child"))
  295. l = s.txGetChildren(c, src)
  296. return nil
  297. })
  298. return l
  299. }
  300. func (s *DB) txGetChildren(b *bolt.Bucket, src DBRef) map[DBRef]string {
  301. l := make(map[DBRef]string)
  302. prefix := src.Key() // 00001234
  303. start := src.ChildKey(0) // 0000123400000000
  304. c := b.Cursor()
  305. for k, v := c.Seek(start); bytes.HasPrefix(k, prefix); k, v = c.Next() {
  306. l[NewDBRefFromChildKey(k)] = string(v)
  307. }
  308. return l
  309. }
  310. func (s *DB) GetParent(src DBRef) (DBRef, bool) {
  311. p := DBRef(0)
  312. f := false
  313. s.db.View(func(tx *bolt.Tx) error {
  314. parentBucket := tx.Bucket([]byte("parent"))
  315. p, f = s.txGetParent(parentBucket, src)
  316. return nil
  317. })
  318. return p, f
  319. }
  320. func (s *DB) txGetParent(parentBucket *bolt.Bucket, childID DBRef) (DBRef, bool) {
  321. parentID := DBRef(0)
  322. f := false
  323. v := parentBucket.Get(childID.Key())
  324. if v != nil {
  325. parentID = NewDBRefFromKey(v)
  326. f = true
  327. }
  328. if DEBUG {
  329. fmt.Printf("txGetParent child: %d parent: %d\n", childID, parentID)
  330. }
  331. //fmt.Printf("txGetParent src: %d found: %t parent: %d\n", src, f, p)
  332. return parentID, f
  333. }
  334. func (s *DB) IsParent(src DBRef, dest DBRef) bool {
  335. f := false
  336. s.db.View(func(tx *bolt.Tx) error {
  337. parentBucket := tx.Bucket([]byte("parent"))
  338. f = s.txIsParent(parentBucket, src, dest)
  339. return nil
  340. })
  341. return f
  342. }
  343. func (s *DB) txIsParent(b *bolt.Bucket, src DBRef, dst DBRef) bool {
  344. v := b.Get(src.Key())
  345. if v != nil {
  346. return (bytes.Compare(v, dst.Key()) == 0)
  347. }
  348. return false
  349. }
  350. func (s *DB) IsChild(src DBRef, dest DBRef) (string, bool) {
  351. t := ""
  352. f := false
  353. s.db.View(func(tx *bolt.Tx) error {
  354. childBucket := tx.Bucket([]byte("child"))
  355. t, f = s.txIsChild(childBucket, src, dest)
  356. return nil
  357. })
  358. return t, f
  359. }
  360. func (s *DB) txIsChild(b *bolt.Bucket, src DBRef, dest DBRef) (string, bool) {
  361. v := b.Get(src.ChildKey(dest))
  362. if v != nil {
  363. return string(v), true
  364. }
  365. return "", false
  366. }
  367. func (s *DB) Link(parentID DBRef, childID DBRef, linkType string) error {
  368. return s.db.Update(func(tx *bolt.Tx) error {
  369. childBucket := tx.Bucket([]byte("child"))
  370. parentBucket := tx.Bucket([]byte("parent"))
  371. return s.txLink(childBucket, parentBucket, parentID, childID, linkType)
  372. })
  373. }
  374. func (s *DB) txLink(childBucket *bolt.Bucket, parentBucket *bolt.Bucket, parentID DBRef, childID DBRef, linkType string) error {
  375. //fmt.Printf("txLink attempting to put %d inside %d\n", childID, parentID)
  376. prevParentID, found := s.txGetParent(parentBucket, childID)
  377. if found {
  378. //fmt.Printf("txLink removing %d from previous parent %d\n", childID, prevParentID)
  379. err := s.txUnlink(childBucket, parentBucket, prevParentID, childID)
  380. if err != nil {
  381. return err
  382. }
  383. }
  384. err := childBucket.Put(parentID.ChildKey(childID), []byte(linkType))
  385. if err != nil {
  386. return err
  387. }
  388. err = parentBucket.Put(childID.Key(), parentID.Key())
  389. if err != nil {
  390. return err
  391. }
  392. if DEBUG {
  393. fmt.Printf("txLink parent: %d child: %d\n", parentID, childID)
  394. }
  395. return nil
  396. }
  397. func (s *DB) Unlink(src DBRef, dest DBRef) error {
  398. return s.db.Update(func(tx *bolt.Tx) error {
  399. childBucket := tx.Bucket([]byte("child"))
  400. parentBucket := tx.Bucket([]byte("parent"))
  401. return s.txUnlink(childBucket, parentBucket, src, dest)
  402. })
  403. }
  404. func (s *DB) txUnlink(childBucket *bolt.Bucket, parentBucket *bolt.Bucket, parentID DBRef, childID DBRef) error {
  405. err := childBucket.Delete(parentID.ChildKey(childID))
  406. if err != nil {
  407. return err
  408. }
  409. err = parentBucket.Delete(childID.Key())
  410. if err != nil {
  411. return err
  412. }
  413. if DEBUG {
  414. fmt.Printf("txUnlink parent: %d child: %d\n", parentID, childID)
  415. }
  416. return nil
  417. }
  418. func (s *DB) txDelete(b *bolt.Bucket, id DBRef) error {
  419. if DEBUG {
  420. fmt.Printf("txDelete %d\n", id)
  421. }
  422. return b.Delete(id.Key())
  423. }