def trade(self, user_1, content_1, user_2, content_2): update_1 = utils.build_update_obj(content_2, neg=content_1) update_2 = utils.build_update_obj(content_1, neg=content_2) self.mongodb.portofolio.update({"user": user_1}, {"$inc": update_1}, safe=True) self.mongodb.portofolio.update({"user": user_2}, {"$inc": update_2}, safe=True)
def trade(self, user1, content1, user2, content2): trade_order = {} trade_order['user_1'] = user1 trade_order['content_1'] = content1 trade_order['user_2'] = user2 trade_order['content_2'] = content2 credit_for_1 = utils.build_update_obj(content2) debit_for_1 = utils.build_update_obj(content1, sign=-1) credit_for_2 = utils.build_update_obj(content1, sign=1) debit_for_2 = utils.build_update_obj(content2, sign=-1) check_1 = utils.build_check_obj(content1) check_2 = utils.build_check_obj(content2) # Insert the transaction in base trade_order['state'] = "running" t_id = self.mongodb.transaction.insert(trade_order, safe=True) check_1.update({ "user":user1, "debited" : { "$ne" : t_id}}) check_2.update({ "user":user2, "debited" : { "$ne" : t_id}}) ## Try to apply all the debits ret = self.mongodb.portofolio.update(check_1, { "$inc" : debit_for_1, "$push" : { "debited" : t_id} }, safe=True ) if not ret['updatedExisting']: self.mongodb.transaction.update({"_id" : t_id}, {"$set" : {"state" : "failed" }}) raise Exception() ret = self.mongodb.portofolio.update(check_2, { "$inc" : debit_for_2, "$push" : { "debited" : t_id } }, safe=True ) if not ret['updatedExisting']: ## Rollback debit on 1 self.mongodb.portofolio.update({"user":user1 } , { "$inc":credit_for_2, "$pull" : { "debited" : t_id }}, safe=True) ## Notify failed transaction self.mongodb.transaction.update({"_id" : t_id}, {"$set" : {"state" : "failed" }}, safe=True) raise Exception() # Notify Sucessfull debits. self.mongodb.transaction.update({"_id" : t_id}, {"$set" : {"state" : "debited" }}, safe=True) if not ret['updatedExisting']: # Rollback ret = self.mongodb.portofolio.update({"user":user1 } , { "$inc":credit_for_2, "$pull" : { "debited" : t_id }}, safe=True) ret = self.mongodb.portofolio.update({"user":user2 } , { "$inc":credit_for_1, "$pull" : { "debited" : t_id }}, safe=True) self.mongodb.transaction.update({"_id" : t_id}, {"$set" : {"state" : "failed" }}, safe=True) raise Exception() # Apply all the credits ret = self.mongodb.portofolio.update({"user": user1}, { "$inc" : credit_for_1,"$pull" : { "debited" : t_id }}, safe=True) if not ret['updatedExisting']: raise Exception() ret = self.mongodb.portofolio.update({"user": user2}, { "$inc" : credit_for_2,"$pull" : { "debited" : t_id }}, safe=True) if not ret['updatedExisting']: raise Exception() # Notify Sucessfull transaction. self.mongodb.transaction.update({"_id" : t_id}, {"$set" : {"state" : "done" }}, safe=True) if not ret['updatedExisting']: raise Exception()
def trade(self, user_1, content_1, user_2, content_2): update_1 = utils.build_update_obj(content_2, neg=content_1) update_2 = utils.build_update_obj(content_1, neg=content_2) check_1 = build_check_obj(content_1) check_2 = build_check_obj(content_2) check_1.update({"user": user_1, "_locked": 1}) check_2.update({"user": user_2, "_locked": 1}) ## Acquire a lock on object. while True: t = time.time() elasped = t - 30 # To lock an object, we set a _locked attributed and a _lock_time # The lock is considered to be valid for only 30 seconds. # A expiring lock is necessary to protect from crash of this thread in mid-air. lock_check_expr = {"$or": [{"_locked": {"$ne": 1}}, {"$le": {"_lock_time": elasped}}]} ret = self.mongodb.portofolio.update( {"$and": [{"user": user_1}, lock_check_expr]}, {"$set": {"_locked": 1, "_lock_time": t}}, safe=True ) if not ret["updatedExisting"]: # Unable to lock the object : retry # (A better implementation would check that the object actually exists in the database, and have some retry limit) time.sleep(0.5) continue ret = self.mongodb.portofolio.update( {"$and": [{"user": user_2}, lock_check_expr]}, {"$set": {"_locked": 1, "_lock_time": t}}, safe=True ) if not ret["updatedExisting"]: # Release lock on 1 self.mongodb.portofolio.update({"user": user_1, "_locked": 1}, {"$unset": {"_locked": 1}}, safe=True) time.sleep(0.5) continue break ## We perform atomically a check on availability and update on each objects, under the common lock ret = self.mongodb.portofolio.update(check_1, {"$inc": update_1}, safe=True) if not ret["updatedExisting"]: raise Exception() ret = self.mongodb.portofolio.update(check_2, {"$inc": update_2}, safe=True) if not ret["updatedExisting"]: raise Exception() ## Release the lock on objects self.mongodb.portofolio.update({"user": user_1, "_locked": 1}, {"$unset": {"_locked": 1}}, safe=True) self.mongodb.portofolio.update({"user": user_2, "_locked": 1}, {"$unset": {"_locked": 1}}, safe=True)
def distribute(self, user, content): update_obj = utils.build_update_obj(content) ret = self.mongodb.portofolio.update({"user": user}, {"$inc": update_obj}, safe=True) if not ret['updatedExisting']: self.mongodb.portofolio.insert({ "user": user, "content": content }, safe=True)
def trade(self, user_1, content_1, user_2, content_2): update_1 = utils.build_update_obj(content_2, neg=content_1) update_2 = utils.build_update_obj(content_1, neg=content_2) check_1 = build_check_obj(content_1) check_2 = build_check_obj(content_2) check_1.update({"user": user_1, "_locked": 1}) check_2.update({"user": user_2, "_locked": 1}) ## Acquire a lock on object. while True: t = time.time() elasped = t - 30 # To lock an object, we set a _locked attributed and a _lock_time # The lock is considered to be valid for only 30 seconds. # A expiring lock is necessary to protect from crash of this thread in mid-air. lock_check_expr = { '$or': [{ "_locked": { "$ne": 1 } }, { "$le": { "_lock_time": elasped } }] } ret = self.mongodb.portofolio.update( {"$and": [{ "user": user_1 }, lock_check_expr]}, {"$set": { "_locked": 1, "_lock_time": t }}, safe=True) if not ret['updatedExisting']: # Unable to lock the object : retry # (A better implementation would check that the object actually exists in the database, and have some retry limit) time.sleep(0.5) continue ret = self.mongodb.portofolio.update( {"$and": [{ "user": user_2 }, lock_check_expr]}, {"$set": { "_locked": 1, "_lock_time": t }}, safe=True) if not ret['updatedExisting']: # Release lock on 1 self.mongodb.portofolio.update({ "user": user_1, "_locked": 1 }, {"$unset": { "_locked": 1 }}, safe=True) time.sleep(0.5) continue break ## We perform atomically a check on availability and update on each objects, under the common lock ret = self.mongodb.portofolio.update(check_1, {"$inc": update_1}, safe=True) if not ret['updatedExisting']: raise Exception() ret = self.mongodb.portofolio.update(check_2, {"$inc": update_2}, safe=True) if not ret['updatedExisting']: raise Exception() ## Release the lock on objects self.mongodb.portofolio.update({ "user": user_1, "_locked": 1 }, {"$unset": { "_locked": 1 }}, safe=True) self.mongodb.portofolio.update({ "user": user_2, "_locked": 1 }, {"$unset": { "_locked": 1 }}, safe=True)
def distribute(self, user, content): update_obj = utils.build_update_obj(content) ret = self.mongodb.portofolio.update({"user": user}, {"$inc": update_obj}, safe=True) if not ret["updatedExisting"]: self.mongodb.portofolio.insert({"user": user, "content": content}, safe=True)
def trade(self, user_1, content_1, user_2, content_2): update_1 = utils.build_update_obj(content_2, neg=content_1) update_2 = utils.build_update_obj(content_1, neg=content_2) self.mongodb.portofolio.update({ "user":user_1 }, { "$inc" : update_1 }, safe=True ) self.mongodb.portofolio.update({ "user":user_2 }, { "$inc" : update_2 }, safe=True )
def trade(self, user1, content1, user2, content2): trade_order = {} trade_order['user_1'] = user1 trade_order['content_1'] = content1 trade_order['user_2'] = user2 trade_order['content_2'] = content2 credit_for_1 = utils.build_update_obj(content2) debit_for_1 = utils.build_update_obj(content1, sign=-1) credit_for_2 = utils.build_update_obj(content1, sign=1) debit_for_2 = utils.build_update_obj(content2, sign=-1) check_1 = utils.build_check_obj(content1) check_2 = utils.build_check_obj(content2) # Insert the transaction in base trade_order['state'] = "running" t_id = self.mongodb.transaction.insert(trade_order, safe=True) check_1.update({"user": user1, "debited": {"$ne": t_id}}) check_2.update({"user": user2, "debited": {"$ne": t_id}}) ## Try to apply all the debits ret = self.mongodb.portofolio.update(check_1, { "$inc": debit_for_1, "$push": { "debited": t_id } }, safe=True) if not ret['updatedExisting']: self.mongodb.transaction.update({"_id": t_id}, {"$set": { "state": "failed" }}) raise Exception() ret = self.mongodb.portofolio.update(check_2, { "$inc": debit_for_2, "$push": { "debited": t_id } }, safe=True) if not ret['updatedExisting']: ## Rollback debit on 1 self.mongodb.portofolio.update({"user": user1}, { "$inc": credit_for_2, "$pull": { "debited": t_id } }, safe=True) ## Notify failed transaction self.mongodb.transaction.update({"_id": t_id}, {"$set": { "state": "failed" }}, safe=True) raise Exception() # Notify Sucessfull debits. self.mongodb.transaction.update({"_id": t_id}, {"$set": { "state": "debited" }}, safe=True) if not ret['updatedExisting']: # Rollback ret = self.mongodb.portofolio.update({"user": user1}, { "$inc": credit_for_2, "$pull": { "debited": t_id } }, safe=True) ret = self.mongodb.portofolio.update({"user": user2}, { "$inc": credit_for_1, "$pull": { "debited": t_id } }, safe=True) self.mongodb.transaction.update({"_id": t_id}, {"$set": { "state": "failed" }}, safe=True) raise Exception() # Apply all the credits ret = self.mongodb.portofolio.update({"user": user1}, { "$inc": credit_for_1, "$pull": { "debited": t_id } }, safe=True) if not ret['updatedExisting']: raise Exception() ret = self.mongodb.portofolio.update({"user": user2}, { "$inc": credit_for_2, "$pull": { "debited": t_id } }, safe=True) if not ret['updatedExisting']: raise Exception() # Notify Sucessfull transaction. self.mongodb.transaction.update({"_id": t_id}, {"$set": { "state": "done" }}, safe=True) if not ret['updatedExisting']: raise Exception()