Browse Source

fix: Better StorageFileError handling

Matthias Ladkau 3 years ago
parent
commit
eddb062c9a

+ 1 - 1
api/v1/blob_test.go

@@ -90,7 +90,7 @@ func TestBlob(t *testing.T) {
 
 	st, _, res = sendTestRequest(queryURL, "POST", []byte{0x0b, 0x00, 0x00, 0x0b, 0x01, 0x0e, 0x05})
 
-	if st != "500 Internal Server Error" || res != "Record is already in-use (? - )" {
+	if st != "500 Internal Server Error" || res != "Record is already in-use (<memory> - )" {
 		t.Error("Unexpected response:", st, res)
 		return
 	}

+ 2 - 2
api/v1/graph_test.go

@@ -315,7 +315,7 @@ func TestGraphQuery(t *testing.T) {
 	st, _, res = sendTestRequest(queryURL+"/main/n/Spam?offset=19&limit=1", "GET", nil)
 
 	if st != "500 Internal Server Error" ||
-		res != "GraphError: Could not read graph information (Record is already in-use (? - ))" {
+		res != "GraphError: Could not read graph information (Record is already in-use (<memory> - ))" {
 		t.Error("Unexpected response:", res)
 		return
 	}
@@ -323,7 +323,7 @@ func TestGraphQuery(t *testing.T) {
 	st, _, res = sendTestRequest(queryURL+"/main/n/Spam", "GET", nil)
 
 	if st != "500 Internal Server Error" ||
-		res != "GraphError: Could not read graph information (Record is already in-use (? - ))" {
+		res != "GraphError: Could not read graph information (Record is already in-use (<memory> - ))" {
 		t.Error("Unexpected response:", res)
 		return
 	}

+ 1 - 1
api/v1/graphql-subscriptions_test.go

@@ -247,7 +247,7 @@ func TestGraphQLSubscription(t *testing.T) {
             "line": 1
           }
         ],
-        "message": "GraphError: Could not read graph information (Record is already in-use (? - ))",
+        "message": "GraphError: Could not read graph information (Record is already in-use (\u003cmemory\u003e - ))",
         "path": [
           "Author"
         ]

+ 1 - 1
cluster/memberaddresstable_test.go

@@ -127,7 +127,7 @@ func TestAddressTableClusterLoc(t *testing.T) {
 	msm.AccessMap[loc] = storage.AccessCacheAndFetchSeriousError
 
 	loc, err = ms1[0].at.NewClusterLoc("test1")
-	if err.Error() != "Record is already in-use (? - )" {
+	if err.Error() != "Record is already in-use (<memory> - )" {
 		t.Error("Unexpected result:", loc, err)
 		return
 	}

+ 1 - 1
eql/interpreter/runtime_test.go

@@ -235,7 +235,7 @@ func TestErrors(t *testing.T) {
 
 	msm.AccessMap[1] = storage.AccessCacheAndFetchSeriousError
 
-	if _, err := rt.nextStartKey(); err.Error() != "GraphError: Could not read graph information (Record is already in-use (? - ))" {
+	if _, err := rt.nextStartKey(); err.Error() != "GraphError: Could not read graph information (Record is already in-use (<memory> - ))" {
 		t.Error(err)
 		return
 	}

+ 31 - 23
graph/graphmanager_edges.go

@@ -448,6 +448,21 @@ func (gm *Manager) StoreEdge(part string, edge data.Edge) error {
 			}
 		}
 
+		defer func() {
+
+			// Flush changes - errors only reported on the actual node storage flush
+
+			gm.gs.FlushMain()
+
+			gm.flushEdgeIndex(part, edge.Kind())
+
+			gm.flushNodeStorage(part, edge.End1Kind())
+
+			gm.flushNodeStorage(part, edge.End2Kind())
+
+			gm.flushEdgeStorage(part, edge.Kind())
+		}()
+
 		// Execute rules
 
 		trans := newInternalGraphTrans(gm)
@@ -465,18 +480,6 @@ func (gm *Manager) StoreEdge(part string, edge data.Edge) error {
 		} else if err := trans.Commit(); err != nil {
 			return err
 		}
-
-		// Flush changes - errors only reported on the actual node storage flush
-
-		gm.gs.FlushMain()
-
-		gm.flushEdgeIndex(part, edge.Kind())
-
-		gm.flushNodeStorage(part, edge.End1Kind())
-
-		gm.flushNodeStorage(part, edge.End2Kind())
-
-		err = gm.flushEdgeStorage(part, edge.Kind())
 	}
 
 	return err
@@ -695,6 +698,21 @@ func (gm *Manager) RemoveEdge(part string, key string, kind string) (data.Edge,
 				return edge, err
 			}
 
+			defer func() {
+
+				// Flush changes - errors only reported on the actual node storage flush
+
+				gm.gs.FlushMain()
+
+				gm.flushEdgeIndex(part, edge.Kind())
+
+				gm.flushNodeStorage(part, edge.End1Kind())
+
+				gm.flushNodeStorage(part, edge.End2Kind())
+
+				gm.flushEdgeStorage(part, edge.Kind())
+			}()
+
 			// Execute rules
 
 			trans := newInternalGraphTrans(gm)
@@ -706,17 +724,7 @@ func (gm *Manager) RemoveEdge(part string, key string, kind string) (data.Edge,
 				return edge, err
 			}
 
-			// Flush changes - errors only reported on the actual node storage flush
-
-			gm.gs.FlushMain()
-
-			gm.flushEdgeIndex(part, edge.Kind())
-
-			gm.flushNodeStorage(part, edge.End1Kind())
-
-			gm.flushNodeStorage(part, edge.End2Kind())
-
-			return edge, gm.flushEdgeStorage(part, edge.Kind())
+			return edge, nil
 		}
 	}
 

+ 25 - 14
graph/graphmanager_nodes.go

@@ -296,6 +296,18 @@ func (gm *Manager) storeOrUpdateNode(part string, node data.Node, onlyUpdate boo
 		}
 	}
 
+	defer func() {
+
+		// Flush changes
+
+		gm.gs.FlushMain()
+
+		gm.flushNodeIndex(part, node.Kind())
+
+		gm.flushNodeStorage(part, node.Kind())
+
+	}()
+
 	// Execute rules
 
 	trans := newInternalGraphTrans(gm)
@@ -314,13 +326,7 @@ func (gm *Manager) storeOrUpdateNode(part string, node data.Node, onlyUpdate boo
 		return err
 	}
 
-	// Flush changes - errors only reported on the actual node storage flush
-
-	gm.gs.FlushMain()
-
-	gm.flushNodeIndex(part, node.Kind())
-
-	return gm.flushNodeStorage(part, node.Kind())
+	return nil
 }
 
 /*
@@ -528,6 +534,17 @@ func (gm *Manager) RemoveNode(part string, key string, kind string) (data.Node,
 				return node, err
 			}
 
+			defer func() {
+
+				// Flush changes
+
+				gm.gs.FlushMain()
+
+				gm.flushNodeIndex(part, kind)
+
+				gm.flushNodeStorage(part, kind)
+			}()
+
 			// Execute rules
 
 			trans := newInternalGraphTrans(gm)
@@ -539,13 +556,7 @@ func (gm *Manager) RemoveNode(part string, key string, kind string) (data.Node,
 				return node, err
 			}
 
-			// Flush changes - errors only reported on the actual node storage flush
-
-			gm.gs.FlushMain()
-
-			gm.flushNodeIndex(part, kind)
-
-			return node, gm.flushNodeStorage(part, kind)
+			return node, nil
 		}
 	}
 

+ 4 - 4
graph/graphmanager_nodes_test.go

@@ -542,7 +542,7 @@ func TestSimpleNodeStorageErrorCases(t *testing.T) {
 	msm.AccessMap[5] = storage.AccessInsertError
 
 	if err := gm.StoreNode("testpart", node2); err.Error() !=
-		"GraphError: Could not write graph information (Record is already in-use (? - ))" {
+		"GraphError: Could not write graph information (Record is already in-use (<memory> - ))" {
 
 		t.Error(err)
 		return
@@ -553,7 +553,7 @@ func TestSimpleNodeStorageErrorCases(t *testing.T) {
 	msm.AccessMap[5] = storage.AccessInsertError
 
 	if err := gm.StoreNode("testpart", node2); err.Error() !=
-		"GraphError: Could not write graph information (Record is already in-use (? - ))" {
+		"GraphError: Could not write graph information (Record is already in-use (<memory> - ))" {
 
 		t.Error(err)
 		return
@@ -599,7 +599,7 @@ func TestSimpleNodeStorageErrorCases(t *testing.T) {
 	node2.SetAttr("key", "789")
 
 	if err := gm.StoreNode("testpart", node2); err.Error() !=
-		"GraphError: Index error (Record is already in-use (? - ))" {
+		"GraphError: Index error (Record is already in-use (<memory> - ))" {
 
 		t.Error(err)
 		return
@@ -608,7 +608,7 @@ func TestSimpleNodeStorageErrorCases(t *testing.T) {
 	node2.SetAttr("key", "123")
 
 	if err := gm.StoreNode("testpart", node2); err.Error() !=
-		"GraphError: Index error (Record is already in-use (? - ))" {
+		"GraphError: Index error (Record is already in-use (<memory> - ))" {
 
 		t.Error(err)
 		return

+ 2 - 1
hash/htree_test.go

@@ -81,7 +81,8 @@ func TestHTree(t *testing.T) {
 
 	sm.AccessMap[1] = storage.AccessInsertError
 
-	if _, err := NewHTree(sm); err != file.ErrAlreadyInUse {
+	_, err := NewHTree(sm)
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error("Unexpected new tree result:", err)
 		return
 	}

+ 4 - 2
hash/htreepage_test.go

@@ -95,7 +95,8 @@ func TestHTreePageInsert(t *testing.T) {
 
 	sm.AccessMap[2] = storage.AccessInsertError
 
-	if _, err := page.Put([]byte("testkey1"), "test1"); err != file.ErrAlreadyInUse {
+	_, err := page.Put([]byte("testkey1"), "test1")
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error("Unexpected put result:", err)
 		return
 	}
@@ -147,7 +148,8 @@ func TestHTreePageInsert(t *testing.T) {
 
 	sm.AccessMap[3] = storage.AccessInsertError
 
-	if _, err := page.Put([]byte("testkey9"), "test9"); err != file.ErrAlreadyInUse {
+	_, err = page.Put([]byte("testkey9"), "test9")
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error("Unexpected put result:", err)
 		return
 	}

+ 1 - 1
hash/iterator_test.go

@@ -207,7 +207,7 @@ func TestIterator(t *testing.T) {
 		return
 	}
 
-	if it.LastError != file.ErrAlreadyInUse {
+	if sfe, ok := it.LastError.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error("Unexpected last error pointer of iterator")
 		return
 	}

+ 5 - 3
storage/cacheddiskstoragemanager_test.go

@@ -181,12 +181,13 @@ func TestCachedDiskStorageManager(t *testing.T) {
 	}
 
 	err = cdsm.Fetch(loc, &ret3)
-	if err != file.ErrAlreadyInUse {
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error("Unexpected fetch result:", ret3, err)
 		return
 	}
 
-	if err := cdsm.Update(loc, "test99"); err != file.ErrAlreadyInUse {
+	err = cdsm.Update(loc, "test99")
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error("Unexpected update result:", err)
 		return
 	}
@@ -266,7 +267,8 @@ func TestCachedDiskStorageManagerTransactions(t *testing.T) {
 		return
 	}
 
-	if err := cdsm.Free(loc2); err != file.ErrAlreadyInUse {
+	err = cdsm.Free(loc2)
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error("Unexpected free result:", err)
 		return
 	}

+ 11 - 9
storage/diskstoragemanager_test.go

@@ -156,7 +156,7 @@ func TestDiskStorageManager1(t *testing.T) {
 	}
 
 	_, err = dsm.Insert(&testutil.GobTestObject{Name: "test", EncErr: false, DecErr: false})
-	if err != file.ErrAlreadyInUse {
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error(err)
 		return
 	}
@@ -170,7 +170,7 @@ func TestDiskStorageManager1(t *testing.T) {
 	}
 
 	_, err = dsm.Insert(&testutil.GobTestObject{Name: "test", EncErr: false, DecErr: false})
-	if err != file.ErrAlreadyInUse {
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error(err, loc)
 	}
 
@@ -264,7 +264,7 @@ func TestDiskStorageManager2(t *testing.T) {
 	record, _ := dsm.logicalSlotsSf.Get(2)
 
 	_, err = dsm.Insert("This is a test")
-	if err != file.ErrAlreadyInUse {
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error(err)
 		return
 	}
@@ -286,13 +286,13 @@ func TestDiskStorageManager2(t *testing.T) {
 	record, _ = dsm.logicalSlotsSf.Get(1)
 
 	err = dsm.Update(loc, "test")
-	if err != file.ErrAlreadyInUse {
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error(err)
 		return
 	}
 
 	err = dsm.Fetch(loc, &res)
-	if err != file.ErrAlreadyInUse {
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error(err)
 		return
 	}
@@ -328,7 +328,7 @@ func TestDiskStorageManager2(t *testing.T) {
 
 	var testres2 testutil.GobTestObject
 	err = dsm.Fetch(loc, &testres2)
-	if err != file.ErrAlreadyInUse {
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error(err)
 		return
 	}
@@ -336,7 +336,7 @@ func TestDiskStorageManager2(t *testing.T) {
 	// Test a normal update
 
 	err = dsm.Update(loc, "tree")
-	if err != file.ErrAlreadyInUse {
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error(err)
 		return
 	}
@@ -471,7 +471,8 @@ func TestDiskStorageManager3(t *testing.T) {
 
 	record, _ := dsm.physicalSlotsSf.Get(1)
 
-	if dsm.Free(loc) != file.ErrAlreadyInUse {
+	err = dsm.Free(loc)
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error("Unexpected free result")
 		return
 	}
@@ -480,7 +481,8 @@ func TestDiskStorageManager3(t *testing.T) {
 
 	record, _ = dsm.logicalSlotsSf.Get(1)
 
-	if dsm.Free(loc) != file.ErrAlreadyInUse {
+	err = dsm.Free(loc)
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error("Unexpected free result")
 		return
 	}

+ 28 - 39
storage/file/storagefile.go

@@ -12,6 +12,7 @@ package file
 
 import (
 	"bytes"
+	"errors"
 	"fmt"
 	"io"
 	"os"
@@ -20,18 +21,15 @@ import (
 )
 
 /*
-Common storage file related errors. Having these global definitions
-makes the error comparison easier but has potential race-conditions.
-If two StorageFile objects throw an error at the same time both errors
-will appear to come from the same instance.
+Common storage file related errors.
 */
 var (
-	ErrAlreadyInUse  = newStorageFileError("Record is already in-use")
-	ErrNotInUse      = newStorageFileError("Record was not in-use")
-	ErrInUse         = newStorageFileError("Records are still in-use")
-	ErrTransDisabled = newStorageFileError("Transactions are disabled")
-	ErrInTrans       = newStorageFileError("Records are still in a transaction")
-	ErrNilData       = newStorageFileError("Record has nil data")
+	ErrAlreadyInUse  = errors.New("Record is already in-use")
+	ErrNotInUse      = errors.New("Record was not in-use")
+	ErrInUse         = errors.New("Records are still in-use")
+	ErrTransDisabled = errors.New("Transactions are disabled")
+	ErrInTrans       = errors.New("Records are still in a transaction")
+	ErrNilData       = errors.New("Record has nil data")
 )
 
 /*
@@ -143,7 +141,7 @@ func (s *StorageFile) Get(id uint64) (*Record, error) {
 
 	// Error if a record which is in-use is requested again before it is released.
 	if _, ok := s.inUse[id]; ok {
-		return nil, ErrAlreadyInUse.fireError(s, fmt.Sprintf("Record %v", id))
+		return nil, NewStorageFileError(ErrAlreadyInUse, fmt.Sprintf("Record %v", id), s.name)
 	}
 
 	// Read the record in from file
@@ -248,7 +246,7 @@ func (s *StorageFile) writeRecord(record *Record) error {
 		return nil
 	}
 
-	return ErrNilData.fireError(s, fmt.Sprintf("Record %v", record.ID()))
+	return NewStorageFileError(ErrNilData, fmt.Sprintf("Record %v", record.ID()), s.name)
 }
 
 /*
@@ -257,7 +255,7 @@ readRecord fills a given record object with data.
 func (s *StorageFile) readRecord(record *Record) error {
 
 	if record.Data() == nil {
-		return ErrNilData.fireError(s, fmt.Sprintf("Record %v", record.ID()))
+		return NewStorageFileError(ErrNilData, fmt.Sprintf("Record %v", record.ID()), s.name)
 	}
 
 	offset := record.ID() * uint64(s.recordSize)
@@ -324,7 +322,7 @@ func (s *StorageFile) ReleaseInUseID(id uint64, dirty bool) error {
 	record, ok := s.inUse[id]
 
 	if !ok {
-		return ErrNotInUse.fireError(s, fmt.Sprintf("Record %v", id))
+		return NewStorageFileError(ErrNotInUse, fmt.Sprintf("Record %v", id), s.name)
 	}
 
 	if !record.Dirty() && dirty {
@@ -371,7 +369,7 @@ writes all dirty records to disk.
 */
 func (s *StorageFile) Flush() error {
 	if len(s.inUse) > 0 {
-		return ErrInUse.fireError(s, fmt.Sprintf("Records %v", len(s.inUse)))
+		return NewStorageFileError(ErrInUse, fmt.Sprintf("Records %v", len(s.inUse)), s.name)
 	}
 
 	if len(s.dirty) == 0 {
@@ -411,11 +409,11 @@ Rollback cancels the current transaction by discarding all dirty records.
 func (s *StorageFile) Rollback() error {
 
 	if s.transDisabled {
-		return ErrTransDisabled.fireError(s, "")
+		return NewStorageFileError(ErrTransDisabled, "", s.name)
 	}
 
 	if len(s.inUse) > 0 {
-		return ErrInUse.fireError(s, fmt.Sprintf("Records %v", len(s.inUse)))
+		return NewStorageFileError(ErrInUse, fmt.Sprintf("Records %v", len(s.inUse)), s.name)
 	}
 
 	s.dirty = make(map[uint64]*Record)
@@ -425,7 +423,7 @@ func (s *StorageFile) Rollback() error {
 	}
 
 	if len(s.inTrans) > 0 {
-		return ErrInTrans.fireError(s, fmt.Sprintf("Records %v", len(s.inTrans)))
+		return NewStorageFileError(ErrInTrans, fmt.Sprintf("Records %v", len(s.inTrans)), s.name)
 	}
 
 	return nil
@@ -464,9 +462,9 @@ func (s *StorageFile) Close() error {
 	}
 
 	if len(s.inTrans) > 0 {
-		return ErrInTrans.fireError(s, fmt.Sprintf("Records %v", len(s.inTrans)))
+		return NewStorageFileError(ErrInTrans, fmt.Sprintf("Records %v", len(s.inTrans)), s.name)
 	} else if len(s.inUse) > 0 {
-		return ErrInUse.fireError(s, fmt.Sprintf("Records %v", len(s.inUse)))
+		return NewStorageFileError(ErrInUse, fmt.Sprintf("Records %v", len(s.inUse)), s.name)
 	}
 
 	for _, file := range s.files {
@@ -552,33 +550,24 @@ func printRecordIDMap(buf *bytes.Buffer, recordMap *map[uint64]*Record, name str
 }
 
 /*
-newStorageFileError returns a new StorageFile specific error.
+StorageFileError is a storage file related error.
 */
-func newStorageFileError(text string) *storagefileError {
-	return &storagefileError{text, "?", ""}
+type StorageFileError struct {
+	Type     error
+	Detail   string
+	Filename string
 }
 
 /*
-StorageFile specific error datastructure
+NewStorageFileError returns a new StorageFile specific error.
 */
-type storagefileError struct {
-	msg      string
-	filename string
-	info     string
-}
-
-/*
-fireError returns the error instance from a specific StorageFile instance.
-*/
-func (e *storagefileError) fireError(s *StorageFile, info string) error {
-	e.filename = s.name
-	e.info = info
-	return e
+func NewStorageFileError(sfeType error, sfeDetail string, sfeFilename string) *StorageFileError {
+	return &StorageFileError{sfeType, sfeDetail, sfeFilename}
 }
 
 /*
 Error returns a string representation of the error.
 */
-func (e *storagefileError) Error() string {
-	return fmt.Sprintf("%s (%s - %s)", e.msg, e.filename, e.info)
+func (e *StorageFileError) Error() string {
+	return fmt.Sprintf("%s (%s - %s)", e.Type.Error(), e.Filename, e.Detail)
 }

+ 16 - 8
storage/file/storagefile_test.go

@@ -246,7 +246,7 @@ func TestLowLevelReadWrite(t *testing.T) {
 
 	err = sf.readRecord(record)
 
-	if err != ErrNilData {
+	if sfe, ok := err.(*StorageFileError); !ok || sfe.Type != ErrNilData {
 		t.Error("Nil pointer in record data should cause an error")
 		return
 	}
@@ -383,7 +383,9 @@ func TestHighLevelGetRelease(t *testing.T) {
 	checkMap(t, &sf.dirty, record3.ID(), false, "Record3", "dirty")
 	checkMap(t, &sf.inUse, record3.ID(), true, "Record3", "in use")
 
-	if err = sf.Flush(); err != ErrInUse {
+	err = sf.Flush()
+
+	if sfe, ok := err.(*StorageFileError); !ok || sfe.Type != ErrInUse {
 		t.Error("StorageFile should complain about records being in use")
 	}
 
@@ -467,7 +469,9 @@ func TestHighLevelGetRelease(t *testing.T) {
 	}
 
 	// Test that requesting a record twice without releasing it causes an error.
-	if _, err = sf.Get(1); err != ErrAlreadyInUse {
+
+	_, err = sf.Get(1)
+	if sfe, ok := err.(*StorageFileError); !ok || sfe.Type != ErrAlreadyInUse {
 		t.Error("Requesting a record which is already in use should cause an error")
 	}
 
@@ -514,7 +518,8 @@ func TestHighLevelGetRelease(t *testing.T) {
 	// An attempt to close the file should return an error
 
 	err = sf.Close()
-	if err != ErrInUse {
+
+	if sfe, ok := err.(*StorageFileError); !ok || sfe.Type != ErrInUse {
 		t.Error("Attempting to close a StorageFile with records in use should " +
 			"return an error")
 		return
@@ -571,13 +576,15 @@ func TestFlushingClosing(t *testing.T) {
 	}
 	record.WriteSingleByte(0, 0)
 
-	if sf.Flush() != ErrInUse {
+	err = sf.Flush()
+	if sfe, ok := err.(*StorageFileError); !ok || sfe.Type != ErrInUse {
 		t.Error("Flushing should not be allowed while records are in use")
 		return
 	}
 
 	sf.ReleaseInUse(nil) // This should not cause a panic
-	if sf.ReleaseInUseID(5000, true) != ErrNotInUse {
+	err = sf.ReleaseInUseID(5000, true)
+	if sfe, ok := err.(*StorageFileError); !ok || sfe.Type != ErrNotInUse {
 		t.Error("It should not be possible to release records which are not in use")
 		return
 	}
@@ -596,7 +603,7 @@ func TestFlushingClosing(t *testing.T) {
 	record.data = nil
 
 	err = sf.Flush()
-	if err != ErrNilData {
+	if sfe, ok := err.(*StorageFileError); !ok || sfe.Type != ErrNilData {
 		t.Error("It should not be possible to flush a record with an invalid id to disk")
 		return
 	}
@@ -638,7 +645,8 @@ func TestFlushingClosing(t *testing.T) {
 	recordData := record.data
 	record.data = nil
 
-	if sf.Close() != ErrNilData {
+	err = sf.Close()
+	if sfe, ok := err.(*StorageFileError); !ok || sfe.Type != ErrNilData {
 		t.Error("Closing with a dirty record with negative id should not be possible", err)
 		return
 	}

+ 6 - 5
storage/file/transactionmanager.go

@@ -22,7 +22,7 @@ import (
 Common TransactionManager related errors
 */
 var (
-	ErrBadMagic = newStorageFileError("Bad magic for transaction log")
+	ErrBadMagic = fmt.Errorf("Bad magic for transaction log")
 )
 
 /*
@@ -107,9 +107,10 @@ func NewTransactionManager(owner *StorageFile, doRecover bool) (*TransactionMana
 		DefaultTransInLog, owner}
 
 	if doRecover {
-		err := ret.recover()
-		if err != nil && err != ErrBadMagic {
-			return nil, err
+		if err := ret.recover(); err != nil {
+			if sfe, ok := err.(*StorageFileError); !ok || sfe.Type != ErrBadMagic {
+				return nil, err
+			}
 		}
 
 		// If we have a bad magic just overwrite the transaction file
@@ -141,7 +142,7 @@ func (t *TransactionManager) recover() error {
 
 	if i != 2 || magic[0] != TransactionLogHeader[0] ||
 		magic[1] != TransactionLogHeader[1] {
-		return ErrBadMagic.fireError(t.owner, "")
+		return NewStorageFileError(ErrBadMagic, "", t.owner.name)
 	}
 
 	for true {

+ 6 - 3
storage/file/transactionmanager_test.go

@@ -423,7 +423,8 @@ func TestRecover(t *testing.T) {
 
 	sf.transDisabled = true
 
-	if err = sf.Close(); err != ErrInTrans {
+	err = sf.Close()
+	if sfe, ok := err.(*StorageFileError); !ok || sfe.Type != ErrInTrans {
 		t.Error(err)
 		return
 	}
@@ -575,7 +576,8 @@ func TestRollbackFail(t *testing.T) {
 	}
 	record.WriteSingleByte(5, 0x42)
 
-	if err = sf.Rollback(); err != ErrInUse {
+	err = sf.Rollback()
+	if sfe, ok := err.(*StorageFileError); !ok || sfe.Type != ErrInUse {
 		t.Error("It should not be possible to rollback while records are still in use")
 	}
 
@@ -599,7 +601,8 @@ func TestRollbackFail(t *testing.T) {
 	}
 
 	sf.inTrans[record.ID()] = record
-	if err = sf.Rollback(); err != ErrInTrans {
+	err = sf.Rollback()
+	if sfe, ok := err.(*StorageFileError); !ok || sfe.Type != ErrInTrans {
 		t.Error("It should not be possible to rollback while records are still in transaction")
 		return
 	}

+ 3 - 3
storage/memorystoragemanager.go

@@ -123,7 +123,7 @@ func (msm *MemoryStorageManager) Insert(o interface{}) (uint64, error) {
 	defer msm.mutex.Unlock()
 
 	if msm.AccessMap[msm.LocCount] == AccessInsertError {
-		return 0, file.ErrAlreadyInUse
+		return 0, file.NewStorageFileError(file.ErrAlreadyInUse, "", "<memory>")
 	}
 	loc := msm.LocCount
 	msm.LocCount++
@@ -172,7 +172,7 @@ func (msm *MemoryStorageManager) Fetch(loc uint64, o interface{}) error {
 	if msm.AccessMap[loc] == AccessFetchError || msm.AccessMap[loc] == AccessCacheAndFetchError {
 		return ErrSlotNotFound.fireError(msm, fmt.Sprint("Location:", loc))
 	} else if msm.AccessMap[loc] == AccessCacheAndFetchSeriousError {
-		return file.ErrAlreadyInUse
+		return file.NewStorageFileError(file.ErrAlreadyInUse, "", "<memory>")
 	}
 
 	if obj, ok := msm.Data[loc]; ok {
@@ -194,7 +194,7 @@ func (msm *MemoryStorageManager) FetchCached(loc uint64) (interface{}, error) {
 	if msm.AccessMap[loc] == AccessNotInCache || msm.AccessMap[loc] == AccessCacheAndFetchError {
 		return nil, ErrNotInCache
 	} else if msm.AccessMap[loc] == AccessCacheAndFetchSeriousError {
-		return nil, file.ErrAlreadyInUse
+		return nil, file.NewStorageFileError(file.ErrAlreadyInUse, "", "<memory>")
 	}
 	return msm.Data[loc], nil
 }

+ 6 - 3
storage/memorystoragemanager_test.go

@@ -84,12 +84,14 @@ func TestMemoryStorageManager(t *testing.T) {
 
 	msm.AccessMap[loc] = AccessCacheAndFetchSeriousError
 
-	if _, err := msm.FetchCached(loc); err != file.ErrAlreadyInUse {
+	_, err := msm.FetchCached(loc)
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error("Unexpected fetchcached result:", err)
 		return
 	}
 
-	if err := msm.Fetch(loc, &ret); err != file.ErrAlreadyInUse {
+	err = msm.Fetch(loc, &ret)
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error("Unexpected fetch result:", err)
 		return
 	}
@@ -117,7 +119,8 @@ func TestMemoryStorageManager(t *testing.T) {
 
 	msm.AccessMap[msm.LocCount] = AccessInsertError
 
-	if _, err := msm.Insert(""); err != file.ErrAlreadyInUse {
+	_, err = msm.Insert("")
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error("Unexpected insert result:", err)
 		return
 	}

+ 2 - 2
storage/paging/pagecursor_test.go

@@ -86,13 +86,13 @@ func TestPageCursor(t *testing.T) {
 	sf.Get(4)
 
 	_, err = pc.Prev()
-	if err != file.ErrAlreadyInUse {
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error("Operation should fail as the required record is in use")
 		return
 	}
 
 	_, err = pc.Next()
-	if err != file.ErrAlreadyInUse {
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error("Operation should fail as the required record is in use")
 		return
 	}

+ 23 - 13
storage/paging/pagedstoragefile_test.go

@@ -68,7 +68,7 @@ func TestPagedStorageFileInitialisation(t *testing.T) {
 	}
 
 	_, err = NewPagedStorageFile(sf)
-	if err != file.ErrAlreadyInUse {
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error("Init of PageStorageFile should fail if header record is not available")
 		return
 	}
@@ -160,7 +160,9 @@ func TestPagedStorageFilePageManagement(t *testing.T) {
 		t.Error(err)
 		return
 	}
-	if err := psf.FreePage(3); err != file.ErrAlreadyInUse {
+
+	err = psf.FreePage(3)
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error(err)
 		return
 	}
@@ -261,7 +263,7 @@ func TestPagedStorageFilePageManagement(t *testing.T) {
 	}
 
 	_, err = psf.AllocatePage(view.TypeTranslationPage)
-	if err != file.ErrAlreadyInUse {
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error(err)
 		return
 	}
@@ -275,7 +277,7 @@ func TestPagedStorageFilePageManagement(t *testing.T) {
 	}
 
 	_, err = psf.AllocatePage(view.TypeTranslationPage)
-	if err != file.ErrAlreadyInUse {
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error(err)
 		return
 	}
@@ -295,7 +297,7 @@ func TestPagedStorageFilePageManagement(t *testing.T) {
 	}
 
 	_, err = psf.AllocatePage(view.TypeTranslationPage)
-	if err != file.ErrAlreadyInUse {
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error(err)
 	}
 
@@ -316,12 +318,14 @@ func TestPagedStorageFilePageManagement(t *testing.T) {
 
 	// Check we can't get Prev info when record is in use
 
-	if _, err := psf.Prev(4); err != file.ErrAlreadyInUse {
+	_, err = psf.Prev(4)
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error(err)
 		return
 	}
 
-	if err := psf.FreePage(2); err != file.ErrAlreadyInUse {
+	err = psf.FreePage(2)
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error(err)
 		return
 	}
@@ -336,7 +340,8 @@ func TestPagedStorageFilePageManagement(t *testing.T) {
 		return
 	}
 
-	if err := psf.FreePage(4); err != file.ErrAlreadyInUse {
+	err = psf.FreePage(4)
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error(err)
 		return
 	}
@@ -354,7 +359,8 @@ func TestPagedStorageFilePageManagement(t *testing.T) {
 		return
 	}
 
-	if err := psf.Close(); err != file.ErrInUse {
+	err = psf.Close()
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrInUse {
 		t.Error(err)
 		return
 	}
@@ -417,7 +423,8 @@ func TestPagedStorageFileTransactionPageManagement(t *testing.T) {
 		return
 	}
 
-	if err := psf.FreePage(3); err != file.ErrAlreadyInUse {
+	err = psf.FreePage(3)
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error(err)
 		return
 	}
@@ -465,7 +472,8 @@ func TestPagedStorageFileTransactionPageManagement(t *testing.T) {
 
 	record, err = sf.Get(4)
 
-	if err := psf.Flush(); err != file.ErrInUse {
+	err = psf.Flush()
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrInUse {
 		t.Error(err)
 		return
 	}
@@ -474,7 +482,8 @@ func TestPagedStorageFileTransactionPageManagement(t *testing.T) {
 
 	psf.header.record = nil
 
-	if err := psf.Flush(); err != file.ErrInUse {
+	err = psf.Flush()
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrInUse {
 		t.Error(err)
 		return
 	}
@@ -483,7 +492,8 @@ func TestPagedStorageFileTransactionPageManagement(t *testing.T) {
 
 	record, err = sf.Get(4)
 
-	if err := psf.Rollback(); err != file.ErrInUse {
+	err = psf.Rollback()
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrInUse {
 		t.Error(err)
 		return
 	}

+ 4 - 2
storage/paging/paging_util_test.go

@@ -54,7 +54,8 @@ func TestFreePhysicalSlotManagerScale(t *testing.T) {
 		return
 	}
 
-	if pc, err := CountPages(psf, view.TypeDataPage); pc != -1 || err != file.ErrAlreadyInUse {
+	pc, err := CountPages(psf, view.TypeDataPage)
+	if sfe, ok := err.(*file.StorageFileError); pc != -1 || !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error("Unexpected page count result:", pc, err)
 		return
 	}
@@ -67,7 +68,8 @@ func TestFreePhysicalSlotManagerScale(t *testing.T) {
 		return
 	}
 
-	if pc, err := CountPages(psf, view.TypeDataPage); pc != -1 || err != file.ErrAlreadyInUse {
+	pc, err = CountPages(psf, view.TypeDataPage)
+	if sfe, ok := err.(*file.StorageFileError); pc != -1 || !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error("Unexpected page count result:", pc, err)
 		return
 	}

+ 9 - 5
storage/slotting/freelogicalslotmanager_test.go

@@ -126,7 +126,8 @@ func TestFreeLogicalSlotManager(t *testing.T) {
 		return
 	}
 
-	if err = flsm.Flush(); err != file.ErrAlreadyInUse {
+	err = flsm.Flush()
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error("Unexpected Get result:", err)
 		return
 	}
@@ -181,7 +182,7 @@ func TestFreeLogicalSlotManager(t *testing.T) {
 	}
 
 	_, err = flsm.Get()
-	if err != file.ErrAlreadyInUse {
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error(err)
 		return
 	}
@@ -310,12 +311,14 @@ func TestFreeLogiclaSlotManagerScale(t *testing.T) {
 		return
 	}
 
-	if err := flsm.Flush(); err != file.ErrAlreadyInUse {
+	err = flsm.Flush()
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error("Unexpected flush result:", err)
 		return
 	}
 
-	if i, err := flsm.doFlush(1, 0); i != 0 || err != file.ErrAlreadyInUse {
+	i, err := flsm.doFlush(1, 0)
+	if sfe, ok := err.(*file.StorageFileError); i != 0 || !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error("Unexpected doFlush result:", i, err)
 		return
 	}
@@ -334,7 +337,8 @@ func TestFreeLogiclaSlotManagerScale(t *testing.T) {
 		return
 	}
 
-	if err := flsm.Flush(); err != file.ErrAlreadyInUse {
+	err = flsm.Flush()
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error("Unexpected flush result:", err)
 		return
 	}

+ 13 - 7
storage/slotting/freephysicalslotmanager_test.go

@@ -217,12 +217,14 @@ func TestFreePhysicalSlotManagerScale(t *testing.T) {
 		return
 	}
 
-	if err := fpsm.Flush(); err != file.ErrAlreadyInUse {
+	err = fpsm.Flush()
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error("Unexpected flush result:", err)
 		return
 	}
 
-	if i, err := fpsm.doFlush(1, 0); i != 0 || err != file.ErrAlreadyInUse {
+	i, err := fpsm.doFlush(1, 0)
+	if sfe, ok := err.(*file.StorageFileError); i != 0 || !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error("Unexpected doFlush result:", i, err)
 		return
 	}
@@ -241,7 +243,8 @@ func TestFreePhysicalSlotManagerScale(t *testing.T) {
 		return
 	}
 
-	if err := fpsm.Flush(); err != file.ErrAlreadyInUse {
+	err = fpsm.Flush()
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error("Unexpected flush result:", err)
 		return
 	}
@@ -293,7 +296,8 @@ func TestFreePhysicalSlotManagerScale(t *testing.T) {
 		return
 	}
 
-	if loc, err := fpsm.Get(499); err != file.ErrAlreadyInUse {
+	loc, err := fpsm.Get(499)
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error("Unexpected Get result:", loc, err)
 		return
 	}
@@ -303,7 +307,7 @@ func TestFreePhysicalSlotManagerScale(t *testing.T) {
 		return
 	}
 
-	loc, err := fpsm.Get(499)
+	loc, err = fpsm.Get(499)
 	if err != nil || loc != 32702963 {
 		t.Error("Unexpected Get result:", err, loc)
 		return
@@ -321,7 +325,8 @@ func TestFreePhysicalSlotManagerScale(t *testing.T) {
 		return
 	}
 
-	if loc, err := fpsm.Get(499); err != file.ErrAlreadyInUse {
+	loc, err = fpsm.Get(499)
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error("Unexpected Get result:", loc, err)
 		return
 	}
@@ -356,7 +361,8 @@ func TestFreePhysicalSlotManagerScale(t *testing.T) {
 		return
 	}
 
-	if err := fpsm.Flush(); err != file.ErrAlreadyInUse {
+	err = fpsm.Flush()
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error("Unexpected Flush result:", err)
 		return
 	}

+ 14 - 7
storage/slotting/logicalslotmanager_test.go

@@ -66,7 +66,8 @@ func TestLogicalSlotManager(t *testing.T) {
 		return
 	}
 
-	if _, err := lsm.Insert(util.PackLocation(10, 11)); err != file.ErrAlreadyInUse {
+	_, err = lsm.Insert(util.PackLocation(10, 11))
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error(err)
 		return
 	}
@@ -81,7 +82,8 @@ func TestLogicalSlotManager(t *testing.T) {
 		return
 	}
 
-	if _, err := lsm.Insert(util.PackLocation(10, 11)); err != file.ErrAlreadyInUse {
+	_, err = lsm.Insert(util.PackLocation(10, 11))
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error(err)
 		return
 	}
@@ -106,7 +108,8 @@ func TestLogicalSlotManager(t *testing.T) {
 		return
 	}
 
-	if err = lsm.ForceInsert(util.PackLocation(2, 2), util.PackLocation(12, 13)); err != file.ErrAlreadyInUse {
+	err = lsm.ForceInsert(util.PackLocation(2, 2), util.PackLocation(12, 13))
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error(err)
 		return
 	}
@@ -128,7 +131,8 @@ func TestLogicalSlotManager(t *testing.T) {
 		return
 	}
 
-	if err = lsm.ForceInsert(util.PackLocation(2, 2), util.PackLocation(12, 13)); err != file.ErrAlreadyInUse {
+	err = lsm.ForceInsert(util.PackLocation(2, 2), util.PackLocation(12, 13))
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error(err)
 		return
 	}
@@ -150,7 +154,8 @@ func TestLogicalSlotManager(t *testing.T) {
 		return
 	}
 
-	if err = lsm.Free(util.PackLocation(2, 2)); err != file.ErrAlreadyInUse {
+	err = lsm.Free(util.PackLocation(2, 2))
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error("Unexpected free result:", err)
 		return
 	}
@@ -171,7 +176,8 @@ func TestLogicalSlotManager(t *testing.T) {
 		return
 	}
 
-	if _, err = lsm.Insert(util.PackLocation(12, 13)); err != file.ErrAlreadyInUse {
+	_, err = lsm.Insert(util.PackLocation(12, 13))
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error("Unexpected free result:", err)
 		return
 	}
@@ -186,7 +192,8 @@ func TestLogicalSlotManager(t *testing.T) {
 		return
 	}
 
-	if err = lsm.Update(util.PackLocation(1, 3), util.PackLocation(12, 13)); err != file.ErrAlreadyInUse {
+	err = lsm.Update(util.PackLocation(1, 3), util.PackLocation(12, 13))
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error("Unexpected update result:", err)
 		return
 	}

+ 26 - 19
storage/slotting/physicalslotmanager_test.go

@@ -136,14 +136,15 @@ func TestPhysicalSlotManager(t *testing.T) {
 	}
 
 	_, err = psm.Insert(make([]byte, 1), 0, 1)
-	if err != file.ErrAlreadyInUse {
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error("Unexpected insert result:", err)
 		return
 	}
 
 	fsf.ReleaseInUse(record)
 
-	if err := psm.Free(util.PackLocation(0, 20)); err != file.ErrAlreadyInUse {
+	err = psm.Free(util.PackLocation(0, 20))
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error("Unexpected free result:", err)
 		return
 	}
@@ -155,7 +156,7 @@ func TestPhysicalSlotManager(t *testing.T) {
 	}
 
 	_, err = psm.allocate(10)
-	if err != file.ErrAlreadyInUse {
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error("Unexpected allocate result:", err)
 		return
 	}
@@ -175,7 +176,7 @@ func TestPhysicalSlotManager(t *testing.T) {
 	// The insert should have failed. The allocated space
 	// for it should have been send back to the free manager
 
-	if err != file.ErrAlreadyInUse {
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error("Unexpected insert result:", err)
 		return
 	}
@@ -194,7 +195,7 @@ func TestPhysicalSlotManager(t *testing.T) {
 	}
 
 	_, err = psm.Insert(arr2, 1, 8999)
-	if err != file.ErrAlreadyInUse {
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error("Unexpected update result:", err)
 		return
 	}
@@ -223,7 +224,7 @@ func TestPhysicalSlotManager(t *testing.T) {
 	}
 
 	_, err = psm.Update(loc, arr2, 1, 8999)
-	if err != file.ErrAlreadyInUse {
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error("Unexpected update result:", err)
 		return
 	}
@@ -237,7 +238,7 @@ func TestPhysicalSlotManager(t *testing.T) {
 	}
 
 	_, err = psm.Update(loc, arr2, 1, 8999)
-	if err != file.ErrAlreadyInUse {
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error("Unexpected update result:", err)
 		return
 	}
@@ -251,7 +252,7 @@ func TestPhysicalSlotManager(t *testing.T) {
 	}
 
 	_, err = psm.Update(loc, arr2, 0, 9000)
-	if err != file.ErrAlreadyInUse {
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error("Unexpected update result:", err)
 		return
 	}
@@ -265,7 +266,7 @@ func TestPhysicalSlotManager(t *testing.T) {
 	}
 
 	_, err = psm.Update(loc, arr2, 0, 9000)
-	if err != file.ErrAlreadyInUse {
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error("Unexpected update result:", err)
 		return
 	}
@@ -470,10 +471,12 @@ func TestPhysicalSlotManagerReadWrite(t *testing.T) {
 		return
 	}
 
-	if err := psm.write(loc2, make([]byte, 0), 0, 0); err != file.ErrAlreadyInUse {
+	err = psm.write(loc2, make([]byte, 0), 0, 0)
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error("Unexpected write result:", err)
 	}
-	if err := psm.Fetch(loc2, buf); err != file.ErrAlreadyInUse {
+	err = psm.Fetch(loc2, buf)
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error("Unexpected read result:", err)
 		return
 	}
@@ -514,10 +517,12 @@ func TestPhysicalSlotManagerReadWrite(t *testing.T) {
 		return
 	}
 
-	if err := psm.write(loc2, make([]byte, 10000), 0, 9999); err != file.ErrAlreadyInUse {
+	err = psm.write(loc2, make([]byte, 10000), 0, 9999)
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error("Unexpected write result:", err)
 	}
-	if err := psm.Fetch(loc2, buf); err != file.ErrAlreadyInUse {
+	err = psm.Fetch(loc2, buf)
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error("Unexpected read result:", err)
 		return
 	}
@@ -536,10 +541,12 @@ func TestPhysicalSlotManagerReadWrite(t *testing.T) {
 		return
 	}
 
-	if err := psm.write(loc3, make([]byte, 10000), 0, 9999); err != file.ErrAlreadyInUse {
+	err = psm.write(loc3, make([]byte, 10000), 0, 9999)
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error("Unexpected write result:", err)
 	}
-	if err := psm.Fetch(loc3, buf); err != file.ErrAlreadyInUse {
+	err = psm.Fetch(loc3, buf)
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error("Unexpected read result:", err)
 		return
 	}
@@ -598,7 +605,7 @@ func TestPhysicalSlotManagerAllocateNew(t *testing.T) {
 	}
 
 	_, err = psm.allocateNew(size, 0)
-	if err != file.ErrAlreadyInUse {
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error(err)
 		return
 	}
@@ -624,7 +631,7 @@ func TestPhysicalSlotManagerAllocateNew(t *testing.T) {
 	}
 
 	_, err = psm.allocateNew(10, 1)
-	if err != file.ErrAlreadyInUse {
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error(err)
 		return
 	}
@@ -776,7 +783,7 @@ func TestPhysicalSlotManagerAllocateNew(t *testing.T) {
 	}
 
 	_, err = psm.allocateNew(8147, 5)
-	if err != file.ErrAlreadyInUse {
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error(err)
 		return
 	}
@@ -801,7 +808,7 @@ func TestPhysicalSlotManagerAllocateNew(t *testing.T) {
 	}
 
 	_, err = psm.allocateNew(8147, 12)
-	if err != file.ErrAlreadyInUse {
+	if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
 		t.Error(err)
 		return
 	}

+ 9 - 8
storage/storagemanager_test.go

@@ -40,16 +40,17 @@ func TestMain(m *testing.M) {
 		os.Exit(1)
 	}
 
-	// Run the tests
-	res := m.Run()
+	defer func() {
+		// Teardown
+		err = os.RemoveAll(DBDIR)
+		if err != nil {
+			fmt.Print("Could not remove test directory:", err.Error())
+		}
+	}()
 
-	// Teardown
-	err = os.RemoveAll(DBDIR)
-	if err != nil {
-		fmt.Print("Could not remove test directory:", err.Error())
-	}
+	// Run the tests
 
-	os.Exit(res)
+	m.Run()
 }
 
 var enableConcurrencyTest = false