github.com/bhojpur/cache@v0.0.4/pkg/file/database/database.go (about) 1 package database 2 3 // Copyright (c) 2018 Bhojpur Consulting Private Limited, India. All rights reserved. 4 5 // Permission is hereby granted, free of charge, to any person obtaining a copy 6 // of this software and associated documentation files (the "Software"), to deal 7 // in the Software without restriction, including without limitation the rights 8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 // copies of the Software, and to permit persons to whom the Software is 10 // furnished to do so, subject to the following conditions: 11 12 // The above copyright notice and this permission notice shall be included in 13 // all copies or substantial portions of the Software. 14 15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 // THE SOFTWARE. 22 23 import ( 24 "encoding/json" 25 "io/ioutil" 26 "os" 27 "path" 28 "time" 29 30 "github.com/bhojpur/cache/pkg/file/common" 31 "github.com/bhojpur/cache/pkg/file/models" 32 "github.com/bhojpur/cache/pkg/file/types" 33 memcache "github.com/bhojpur/cache/pkg/memory" 34 ) 35 36 // DBType represents the type of database of the instance, either a node's 37 // shard database or the main file database. 38 type DBType int 39 40 const ( 41 // FILEDB the marker for a file database. 42 FILEDB DBType = iota 43 44 // NSHARDDB is the marker for the node's shard database. 45 NSHARDDB DBType = iota 46 ) 47 48 // fileDBBucket is the bucket used to store files within a filedb. 49 var fileDBBucket = []byte("files") 50 51 // nshardDBBucket is the bucket used to store shards within a shard database. 52 var nshardDBBucket = []byte("shards") 53 54 // Database implements a general database that holds various data within meros. 55 type Database struct { 56 Header types.DatabaseHeader `json:"header"` // Database header info 57 Name string `json:"name"` // The name of the db 58 DBType DBType // The type of database 59 60 DB *memcache.DB // Bhojpur Cache in-memory databse instance 61 bucket []byte // The bucket for the database 62 open bool // Status of the DB 63 } 64 65 // Open opens the database for reading and writing. Creates a new DB if one 66 // with that name does not already exist. 67 func Open(dbName string, dbType DBType) (*Database, error) { 68 // Make sure path exists 69 err := common.CreateDirIfDoesNotExist(path.Join(models.DBPath, dbName)) 70 if err != nil { 71 return nil, err 72 } 73 74 var database *Database // The database to return 75 76 // Prepare to serialize the database struct 77 databasePath := path.Join(models.DBPath, dbName, "db.json") 78 if _, err := os.Stat(databasePath); err != nil { // If DB name does not exist 79 // Create the database struct 80 database = &Database{ 81 Header: types.NewDatabaseHeader(dbName), // Generate and set header 82 83 Name: dbName, // Set the name 84 } 85 86 err = database.serialize(databasePath) // Write the db struct to disk 87 if err != nil { 88 return nil, err 89 } 90 91 } else { 92 // If the db does exist, read from it and return it 93 database, err = deserialize(databasePath) 94 if err != nil { 95 return nil, err 96 } 97 } 98 99 // Prepare to open the Bhojpur Cache in-memory database 100 memdbPath := path.Join(models.DBPath, dbName, "bhojpur-cache.db") 101 db, err := memcache.Open(memdbPath, 0600, &memcache.Options{ // Open the DB 102 Timeout: 1 * time.Second, 103 }) 104 if err != nil { 105 return nil, err 106 } 107 108 database.DB = db // Set the DB 109 database.DBType = dbType // Set the type of database 110 111 // Bucket handler 112 switch dbType { 113 case FILEDB: // If FileDB type, set to the corresponding bucket 114 database.bucket = fileDBBucket 115 case NSHARDDB: // If NodeShardDB type, set to the corresponding bucket 116 database.bucket = nshardDBBucket 117 } 118 119 err = database.makeBuckets() // Make the buckets in the database 120 if err != nil { 121 return nil, err 122 } 123 124 database.open = true // Set the status to open 125 126 return database, nil 127 } 128 129 // Close closes the database. 130 func (db *Database) Close() error { 131 err := db.DB.Close() // Close the DB 132 if err != nil { 133 return err 134 } 135 136 db.open = false // Set DB status 137 return nil 138 } 139 140 // makeBuckets constructs the buckets in the database. 141 func (db *Database) makeBuckets() error { 142 // Create all buckets in the database 143 err := db.DB.Update(func(tx *memcache.Tx) error { // Open tx for bucket creation 144 _, err := tx.CreateBucketIfNotExists(db.bucket) // Create bucket 145 return err // Handle err 146 }) 147 if err != nil { // Check the err 148 return err 149 } 150 return err 151 } 152 153 // String marshals the DB as a string. 154 func (db *Database) String() string { 155 json, _ := json.MarshalIndent(*db, "", " ") 156 return string(json) 157 } 158 159 // serialize will serialize the database and write it to disk. 160 func (db *Database) serialize(filepath string) error { 161 json, _ := json.MarshalIndent(*db, "", " ") 162 err := ioutil.WriteFile(filepath, json, 0600) 163 return err 164 } 165 166 // deserialize will deserialize the database from the disk 167 func deserialize(filepath string) (*Database, error) { 168 data, err := ioutil.ReadFile(filepath) // Read the database from disk 169 if err != nil { 170 return nil, err 171 } 172 173 buffer := &Database{} // Initialize the database buffer 174 175 // Unmarshal and write into the buffer 176 err = json.Unmarshal(data, buffer) 177 178 return buffer, err 179 }