1
0
mirror of https://github.com/jhillyerd/inbucket.git synced 2025-12-21 11:37:07 +00:00

More index.gob work

Use a global lock for reading/writing any index file.  Possible
bottleneck, but good enough for now.

Don't create a mailbox directory until a message is being written to it.
This commit is contained in:
James Hillyerd
2013-10-11 20:06:33 -07:00
parent 789105b9fd
commit 08f16db7ac
2 changed files with 198 additions and 97 deletions

View File

@@ -13,11 +13,17 @@ import (
"net/mail"
"os"
"path/filepath"
"sync"
"time"
)
// Name of index file in each mailbox
const INDEX_FILE = "index.gob"
// We lock this when reading/writing an index file, this is a bottleneck because
// it's a single lock even if we have a million index files
var indexLock = new(sync.RWMutex)
var ErrNotWritable = errors.New("Message not writable")
// Global because we only want one regardless of the number of DataStore objects
@@ -55,6 +61,10 @@ func NewFileDataStore() DataStore {
return nil
}
mailPath := filepath.Join(path, "mail")
if _, err := os.Stat(mailPath); err != nil {
// Mail datastore does not yet exist
os.MkdirAll(mailPath, 0770)
}
return &FileDataStore{path: path, mailPath: mailPath}
}
@@ -67,19 +77,6 @@ func (ds *FileDataStore) MailboxFor(emailAddress string) (Mailbox, error) {
s2 := dir[0:6]
path := filepath.Join(ds.mailPath, s1, s2, dir)
indexPath := filepath.Join(path, INDEX_FILE)
if err := os.MkdirAll(path, 0770); err != nil {
log.LogError("Failed to create directory %v, %v", path, err)
return nil, err
}
if _, err := os.Stat(indexPath); err != nil {
// index does not yet exist, create empty one
if file, err := os.Create(indexPath); err != nil {
log.LogError("Failed to create index %v, %v", indexPath, err)
return nil, err
} else {
file.Close()
}
}
return &FileMailbox{store: ds, name: name, dirName: dir, path: path,
indexPath: indexPath}, nil
@@ -180,6 +177,16 @@ func (mb *FileMailbox) GetMessage(id string) (Message, error) {
func (mb *FileMailbox) readIndex() error {
// Clear message slice, open index
mb.messages = mb.messages[:0]
// Lock for reading
indexLock.RLock()
defer indexLock.RUnlock()
// Check if index exists
if _, err := os.Stat(mb.indexPath); err != nil {
// Does not exist, but that's not an error in our world
log.LogTrace("Index %v does not exist (yet)", mb.indexPath)
mb.indexLoaded = true
return nil
}
file, err := os.Open(mb.indexPath)
if err != nil {
return err
@@ -207,8 +214,26 @@ func (mb *FileMailbox) readIndex() error {
return nil
}
// createDir checks for the presence of the path for this mailbox, creates it if needed
func (mb *FileMailbox) createDir() error {
if _, err := os.Stat(mb.path); err != nil {
if err := os.MkdirAll(mb.path, 0770); err != nil {
log.LogError("Failed to create directory %v, %v", mb.path, err)
return err
}
}
return nil
}
// writeIndex overwrites the index on disk with the current mailbox data
func (mb *FileMailbox) writeIndex() error {
// Lock for writing
indexLock.Lock()
defer indexLock.Unlock()
// Ensure mailbox directory exists
if err := mb.createDir(); err != nil {
return err
}
// Open index for writing
file, err := os.Create(mb.indexPath)
if err != nil {
@@ -349,6 +374,10 @@ func (m *FileMessage) Append(data []byte) error {
}
// Open file for writing if we haven't yet
if m.writer == nil {
// Ensure mailbox directory exists
if err := m.mailbox.createDir(); err != nil {
return err
}
file, err := os.Create(m.rawPath())
if err != nil {
// Set writable false just in case something calls me a million times
@@ -413,6 +442,7 @@ func (m *FileMessage) Delete() error {
break
}
}
m.mailbox.writeIndex()
log.LogTrace("Deleting %v", m.rawPath())
return os.Remove(m.rawPath())