// PurgeMissing removes from collections any state that refers to transaction // documents that for whatever reason have been lost from the system (removed // by accident or lost in a hard crash, for example). // // This method should very rarely be needed, if at all, and should never be // used during the normal operation of an application. Its purpose is to put // a system that has seen unavoidable corruption back in a working state. func (r *Runner) PurgeMissing(collections ...string) error { type M map[string]interface{} type S []interface{} type TDoc struct { Id interface{} "_id" TxnQueue []string "txn-queue" } found := make(map[bson.ObjectId]bool) sort.Strings(collections) for _, collection := range collections { c := r.tc.Database.C(collection) iter := c.Find(nil).Select(bson.M{"_id": 1, "txn-queue": 1}).Iter() var tdoc TDoc for iter.Next(&tdoc) { for _, txnToken := range tdoc.TxnQueue { txnId := bson.ObjectIdHex(txnToken[:24]) if found[txnId] { continue } if r.tc.FindId(txnId).One(nil) == nil { found[txnId] = true continue } logf("WARNING: purging from document %s/%v the missing transaction id %s", collection, tdoc.Id, txnId) err := c.UpdateId(tdoc.Id, M{"$pull": M{"txn-queue": M{"$regex": "^" + txnId.Hex() + "_*"}}}) if err != nil { return fmt.Errorf("error purging missing transaction %s: %v", txnId.Hex(), err) } } } if err := iter.Close(); err != nil { return fmt.Errorf("transaction queue iteration error for %s: %v", collection, err) } } type StashTDoc struct { Id docKey "_id" TxnQueue []string "txn-queue" } iter := r.sc.Find(nil).Select(bson.M{"_id": 1, "txn-queue": 1}).Iter() var stdoc StashTDoc for iter.Next(&stdoc) { for _, txnToken := range stdoc.TxnQueue { txnId := bson.ObjectIdHex(txnToken[:24]) if found[txnId] { continue } if r.tc.FindId(txnId).One(nil) == nil { found[txnId] = true continue } logf("WARNING: purging from stash document %s/%v the missing transaction id %s", stdoc.Id.C, stdoc.Id.Id, txnId) err := r.sc.UpdateId(stdoc.Id, M{"$pull": M{"txn-queue": M{"$regex": "^" + txnId.Hex() + "_*"}}}) if err != nil { return fmt.Errorf("error purging missing transaction %s: %v", txnId.Hex(), err) } } } if err := iter.Close(); err != nil { return fmt.Errorf("transaction stash iteration error: %v", err) } return nil }
func (tt token) id() bson.ObjectId { return bson.ObjectIdHex(string(tt[:24])) }