Initial commit
This commit is contained in:
		
							
								
								
									
										162
									
								
								mdb/testing/crashconsistency/main.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										162
									
								
								mdb/testing/crashconsistency/main.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,162 @@ | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"crypto/rand" | ||||
| 	"errors" | ||||
| 	"hash/crc32" | ||||
| 	"git.crumpington.com/public/jldb/mdb" | ||||
| 	"log" | ||||
| 	mrand "math/rand" | ||||
| 	"os" | ||||
| 	"runtime" | ||||
| 	"slices" | ||||
| 	"sync" | ||||
| 	"sync/atomic" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| type DataItem struct { | ||||
| 	ID   uint64 | ||||
| 	Data []byte | ||||
| } | ||||
|  | ||||
| type DataCollection struct { | ||||
| 	*mdb.Collection[DataItem] | ||||
| } | ||||
|  | ||||
| func NewDataCollection(db *mdb.Database) DataCollection { | ||||
| 	return DataCollection{ | ||||
| 		Collection: mdb.NewCollection(db, "Data", &mdb.CollectionConfig[DataItem]{ | ||||
| 			Copy: func(in *DataItem) *DataItem { | ||||
| 				out := new(DataItem) | ||||
| 				*out = *in | ||||
| 				out.Data = slices.Clone(in.Data) | ||||
| 				return out | ||||
| 			}, | ||||
| 		}), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| type CRCItem struct { | ||||
| 	ID    uint64 // Always 1 | ||||
| 	CRC32 uint32 | ||||
| } | ||||
|  | ||||
| type CRCCollection struct { | ||||
| 	*mdb.Collection[CRCItem] | ||||
| } | ||||
|  | ||||
| func NewCRCCollection(db *mdb.Database) CRCCollection { | ||||
| 	return CRCCollection{ | ||||
| 		Collection: mdb.NewCollection[CRCItem](db, "CRC", nil), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| type DataDB struct { | ||||
| 	*mdb.Database | ||||
| 	Datas DataCollection | ||||
| 	CRCs  CRCCollection | ||||
| } | ||||
|  | ||||
| func OpenDataDB(rootDir string) (DataDB, error) { | ||||
| 	db := mdb.New(mdb.Config{RootDir: rootDir, Primary: true}) | ||||
| 	testdb := DataDB{ | ||||
| 		Database: db, | ||||
| 		Datas:    NewDataCollection(db), | ||||
| 		CRCs:     NewCRCCollection(db), | ||||
| 	} | ||||
|  | ||||
| 	if err := db.Open(); err != nil { | ||||
| 		return testdb, err | ||||
| 	} | ||||
|  | ||||
| 	return testdb, nil | ||||
| } | ||||
|  | ||||
| func (db DataDB) ModifyFor(dt time.Duration) { | ||||
| 	wg := sync.WaitGroup{} | ||||
| 	var count int64 | ||||
| 	for i := 0; i < runtime.NumCPU(); i++ { | ||||
| 		wg.Add(1) | ||||
| 		go func() { | ||||
| 			defer wg.Done() | ||||
|  | ||||
| 			t0 := time.Now() | ||||
| 			for time.Since(t0) < dt { | ||||
| 				atomic.AddInt64(&count, 1) | ||||
| 				db.modifyOnce() | ||||
| 			} | ||||
| 		}() | ||||
| 	} | ||||
|  | ||||
| 	wg.Wait() | ||||
| 	log.Printf("Modified: %d", count) | ||||
| } | ||||
|  | ||||
| func (db DataDB) modifyOnce() { | ||||
| 	isErr := mrand.Float64() < 0.1 | ||||
| 	err := db.Update(func(tx *mdb.Snapshot) error { | ||||
| 		h := crc32.NewIEEE() | ||||
| 		for dataID := uint64(1); dataID < 10; dataID++ { | ||||
| 			d := DataItem{ | ||||
| 				ID:   dataID, | ||||
| 				Data: make([]byte, 256), | ||||
| 			} | ||||
|  | ||||
| 			rand.Read(d.Data) | ||||
| 			h.Write(d.Data) | ||||
| 			if err := db.Datas.Upsert(tx, &d); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		crc := CRCItem{ | ||||
| 			ID: 1, | ||||
| 		} | ||||
|  | ||||
| 		if !isErr { | ||||
| 			crc.CRC32 = h.Sum32() | ||||
| 			return db.CRCs.Upsert(tx, &crc) | ||||
| 		} | ||||
|  | ||||
| 		crc.CRC32 = 1 | ||||
| 		if err := db.CRCs.Upsert(tx, &crc); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
|  | ||||
| 		return errors.New("ERROR") | ||||
| 	}) | ||||
|  | ||||
| 	if isErr != (err != nil) { | ||||
| 		panic(err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (db DataDB) ComputeCRC(tx *mdb.Snapshot) uint32 { | ||||
| 	h := crc32.NewIEEE() | ||||
| 	for dataID := uint64(1); dataID < 10; dataID++ { | ||||
| 		d, ok := db.Datas.ByID.Get(tx, &DataItem{ID: dataID}) | ||||
| 		if !ok { | ||||
| 			continue | ||||
| 		} | ||||
| 		h.Write(d.Data) | ||||
| 	} | ||||
| 	return h.Sum32() | ||||
| } | ||||
|  | ||||
| func (db DataDB) ReadCRC(tx *mdb.Snapshot) uint32 { | ||||
| 	r, ok := db.CRCs.ByID.Get(tx, &CRCItem{ID: 1}) | ||||
| 	if !ok { | ||||
| 		return 0 | ||||
| 	} | ||||
| 	return r.CRC32 | ||||
| } | ||||
|  | ||||
| func main() { | ||||
| 	db, err := OpenDataDB(os.Args[1]) | ||||
| 	if err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	db.ModifyFor(time.Minute) | ||||
| } | ||||
		Reference in New Issue
	
	Block a user