package mdb import ( "crypto/rand" "errors" "hash/crc32" "log" mrand "math/rand" "runtime" "slices" "sync" "sync/atomic" "time" ) type DataItem struct { ID uint64 Data []byte } type DataCollection struct { *Collection[DataItem] } func NewDataCollection(db *Database) DataCollection { return DataCollection{ Collection: NewCollection(db, "Data", &CollectionConfig[DataItem]{ Copy: func(in *DataItem) *DataItem { out := &DataItem{} *out = *in out.Data = slices.Clone(in.Data) return out }, }), } } type CRCItem struct { ID uint64 // Always 1 CRC32 uint32 } type CRCCollection struct { *Collection[CRCItem] } func NewCRCCollection(db *Database) CRCCollection { return CRCCollection{ Collection: NewCollection[CRCItem](db, "CRC", nil), } } type DataDB struct { *Database Datas DataCollection CRCs CRCCollection } func OpenDataDB(rootDir string) (DataDB, error) { db := New(Config{ RootDir: rootDir, Primary: true, }) testdb := DataDB{ Database: db, Datas: NewDataCollection(db), CRCs: NewCRCCollection(db), } return testdb, testdb.Open() } 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 *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 *Snapshot) uint32 { h := crc32.NewIEEE() for dataID := uint64(1); dataID < 10; dataID++ { d := db.Datas.ByID.Get(tx, &DataItem{ID: dataID}) if d == nil { continue } h.Write(d.Data) } return h.Sum32() } func (db DataDB) ReadCRC(tx *Snapshot) uint32 { r := db.CRCs.ByID.Get(tx, &CRCItem{ID: 1}) if r == nil { return 0 } return r.CRC32 }