Compare commits

..

No commits in common. "7847236dbc9e9584ea35f62cade8b77b29f208d6" and "59e315cf95088ea86927e684a09071d81dfd06fa" have entirely different histories.

3 changed files with 25 additions and 24 deletions

View File

@ -1,7 +1,8 @@
Copyright (c) 2017, Přemysl Janouch <p@janouch.name>
Copyright (c) 2017, Přemysl Janouch <p.janouch@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF

24
db.go
View File

@ -12,20 +12,20 @@ import (
var ErrClosed = errors.New("database has been closed")
type DB struct {
sync.RWMutex // locking
data map[string]string // current state of the database
file *os.File // data storage
sync.RWMutex // Locking
data map[string]string // Current state of the database
file *os.File // Data storage
}
// OpenDB opens an existing database file, loading the contents to memory.
// Open an existing database file, loading the contents to memory
func OpenDB(path string) (*DB, error) {
file, err := os.OpenFile(path, os.O_RDWR, 0 /* not used */)
if err != nil {
return nil, err
}
// TODO: We might want a recover flag that just reads as much as it can
// instead of returning io.ErrUnexpectedEOF.
// TODO we might want a recover flag that just reads as much as it can
// instead of returning io.ErrUnexpectedEOF
db := &DB{data: make(map[string]string), file: file}
for {
var header struct{ KeyLen, ValueLen int32 }
@ -64,7 +64,7 @@ func OpenDB(path string) (*DB, error) {
return db, nil
}
// CreateDB creates a new database, overwriting any previous file contents.
// Create a new database, overwriting any previous contents of the file
func CreateDB(path string) (*DB, error) {
file, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
@ -73,7 +73,7 @@ func CreateDB(path string) (*DB, error) {
return &DB{data: make(map[string]string), file: file}, nil
}
// Get retrieves the value corresponding to the given key.
// Retrieve the value corresponding to the given key
func (db *DB) Get(key string) (string, bool, error) {
db.RLock()
defer db.RUnlock()
@ -106,7 +106,7 @@ func put(file *os.File, key, value string) error {
return nil
}
// Put saves a key-value pair in the database storage.
// Save a key-value pair in the database storage
func (db *DB) Put(key, value string) error {
db.Lock()
defer db.Unlock()
@ -127,7 +127,7 @@ func (db *DB) Put(key, value string) error {
return nil
}
// Delete deletes a key from the database storage.
// Delete a key from the database storage
func (db *DB) Delete(key string) error {
db.Lock()
defer db.Unlock()
@ -157,7 +157,7 @@ func (db *DB) Delete(key string) error {
return nil
}
// Checkpoint gets rid of historical data in the database file.
// Get rid of historical data in the database file
func (db *DB) Checkpoint() error {
db.Lock()
defer db.Unlock()
@ -194,7 +194,7 @@ func (db *DB) Checkpoint() error {
return nil
}
// Close closes the database file, rendering the object unusable.
// Close the database file, rendering the object unusable
func (db *DB) Close() error {
db.Lock()
defer db.Unlock()

20
main.go
View File

@ -1,4 +1,4 @@
// Demos a trivial key-value database backed by a file.
// Demos a trivial key-value database backed by a file
package main
import (
@ -14,7 +14,7 @@ import (
func main() {
if len(os.Args) != 3 {
log.Fatalf("Usage: %s LISTEN-ADDRESS DATABASE-FILE\n", os.Args[0])
log.Fatalln("usage: %s LISTEN-ADDRESS DATABASE-FILE", os.Args[0])
}
listenAddr, dbFilename := os.Args[1], os.Args[2]
@ -66,18 +66,18 @@ func main() {
})
server := &http.Server{Addr: listenAddr}
errs := make(chan error, 1)
go func() { errs <- server.ListenAndServe() }()
go func() {
if err := http.ListenAndServe(listenAddr, nil); err != nil &&
err != http.ErrServerClosed {
log.Fatalln(err)
}
}()
sig := make(chan os.Signal)
signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
select {
case <-sig:
case err := <-errs:
log.Println(err)
}
<-sig
// For simplicity, we'll wait for everything to finish, including snapshots.
// For simplicity, we'll wait for everything to finish, including snapshots
if err := server.Shutdown(context.Background()); err != nil {
log.Fatalln(err)
}