Compare commits

...

4 Commits

Author SHA1 Message Date
Přemysl Eric Janouch 7847236dbc
Improve server shutdown
Less likely to corrupt data now.
2019-04-19 12:30:48 +02:00
Přemysl Eric Janouch 0fcc67c121
Fix the usage message 2019-04-19 12:30:13 +02:00
Přemysl Eric Janouch c7597b73c2
Style fixes 2019-04-19 12:30:01 +02:00
Přemysl Eric Janouch 47de2cebaa
Relicense to 0BSD, update mail address
I've come to the conclusion that copyright mostly just stands in the way
of software development.  In my jurisdiction I cannot give up my own
copyright and 0BSD seems to be the closest thing to public domain.

The updated mail address, also used in my author/committer lines,
is shorter and looks nicer.  People rarely interact anyway.
2018-06-24 05:30:32 +02:00
3 changed files with 24 additions and 25 deletions

View File

@ -1,8 +1,7 @@
Copyright (c) 2017, Přemysl Janouch <p.janouch@gmail.com>
Copyright (c) 2017, Přemysl Janouch <p@janouch.name>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
purpose with or without fee is hereby granted.
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
}
// Open an existing database file, loading the contents to memory
// OpenDB opens 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
}
// Create a new database, overwriting any previous contents of the file
// CreateDB creates a new database, overwriting any previous file contents.
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
}
// Retrieve the value corresponding to the given key
// Get retrieves 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
}
// Save a key-value pair in the database storage
// Put saves 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 a key from the database storage
// Delete deletes 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
}
// Get rid of historical data in the database file
// Checkpoint gets 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 the database file, rendering the object unusable
// Close closes 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.Fatalln("usage: %s LISTEN-ADDRESS DATABASE-FILE", os.Args[0])
log.Fatalf("Usage: %s LISTEN-ADDRESS DATABASE-FILE\n", os.Args[0])
}
listenAddr, dbFilename := os.Args[1], os.Args[2]
@ -66,18 +66,18 @@ func main() {
})
server := &http.Server{Addr: listenAddr}
go func() {
if err := http.ListenAndServe(listenAddr, nil); err != nil &&
err != http.ErrServerClosed {
log.Fatalln(err)
}
}()
errs := make(chan error, 1)
go func() { errs <- server.ListenAndServe() }()
sig := make(chan os.Signal)
signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
<-sig
select {
case <-sig:
case err := <-errs:
log.Println(err)
}
// 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)
}