[mnet-devel] patch: don't use bsddb in counterparties.py
Zooko O'Whielacronx
zooko at zooko.com
Tue Apr 6 17:23:08 BST 2004
This removes bsddb from counterparties.py and replaces it with no persistence!
The downside is that nodes don't remember historical msg turnaround times after
they get restarted. The upsides are:
(a) one less use of BerkeleyDB -- hooray!,
(b) counterparties.py downsized from 648 lines of code to 76 lines. (Tons of
obsolete stuff was removed -- mojo offers, token payments, reliability
measures, amount will front, temporary amount will front,
SelfCounterPartyObject...),
(c) counterparties.py doesn't need to touch the disk anymore, which is always
nice for performance, being lightweight, etc.
So I'll probably commit this to HEAD branch sometime. By the way, <h8ric> is
running this patch.
--Z
-------------- next part --------------
Index: egtp/MojoTransaction.py
===================================================================
RCS file: /cvsroot/mnet/mnet_new/egtp/MojoTransaction.py,v
retrieving revision 1.38
diff -p -u -r1.38 MojoTransaction.py
--- egtp/MojoTransaction.py 16 Jan 2004 23:53:31 -0000 1.38
+++ egtp/MojoTransaction.py 6 Apr 2004 16:00:48 -0000
@@ -276,7 +276,7 @@ class MojoTransactionManager:
self._listenermanager = ListenerManager.ListenerManager(cryptol=self._ch, tcpl=tcpch, relayl=RelayListener.RelayListener(self, discoveryman=self._discoveryman, neverpoll=neverpoll), mtm=self, allownonrouteableip=allownonrouteableip)
- self._keeper=counterparties.CounterpartyObjectKeeper(dbparentdir=self._datadir, local_id=self.get_id(), recoverdb=True)
+ self._keeper=counterparties.CounterpartyObjectKeeper(dbparentdir=self._datadir, nodeId=self.get_id())
# this is used to prevent >1 update from occurring at the same time
self.__handler_funcs_and_services_dicts_update_lock=threading.Lock()
@@ -874,13 +874,10 @@ class MojoTransactionManager:
debugprint("MTM: msgId: %s :: %s with %s, failed, failure_reason: %s\n", args=(widget._firstmsgId, conversationtype, widget.get_counterparty_id(), failure_reason), v=2, vs="Conversation")
self.forget_comm_strategy(counterparty_id, widget._firstmsgId, outcome=outcome, failure_reason=failure_reason)
- counterparty_obj.decrement_reliability()
if outer_outcome_func:
return apply(outer_outcome_func, (), {'widget': widget, 'outcome': outcome, 'failure_reason': failure_reason})
else:
return None
- else:
- counterparty_obj.increment_reliability()
debugprint("MTM: msgId: %s :: %s with %s, completed\n", args=(widget._firstmsgId, conversationtype, widget.get_counterparty_id(),), v=2, vs="Conversation")
@@ -925,8 +922,6 @@ class MojoTransactionManager:
if not idlib.is_sloppy_id(counterparty_id):
debugprint("WARNING: I want a counterparty_id here. counterparty_id: %s :: %s, msgId: %s, failure_reason: %s, stack trace: %s\n", args=(counterparty_id, type(counterparty_id), msgId, failure_reason, traceback.extract_stack(),), v=1, vs="debug")
else:
- # failure? count that against their reliability
- counterparty_obj = self._keeper.get_counterparty_object(counterparty_id).decrement_reliability()
# MetaTrackerLib.neg_contact_info(counterparty_id) # commenting this out in an attempt to separate MetaTrackerLib from MojoTransaction, during the "nEGTP-1" era. (that is: MetaTrackerLib will hopefully be managed solely by MetaTrackerLookupMan from now on. This suggests that MTL should not do any caching at all, so that we don't have to neg-cache it. The Crypto and TCP Comms Handlers are both doing some limited caching already.) --Zooko 2002-01-28
self.forget_comm_strategy(counterparty_id, firstmsgId=msgId, failure_reason=failure_reason)
Index: egtp/counterparties.py
===================================================================
RCS file: /cvsroot/mnet/mnet_new/egtp/counterparties.py,v
retrieving revision 1.14
diff -p -u -r1.14 counterparties.py
--- egtp/counterparties.py 4 Nov 2003 23:10:24 -0000 1.14
+++ egtp/counterparties.py 6 Apr 2004 16:00:48 -0000
@@ -1,5 +1,5 @@
# Copyright (c) 2000 HiveCache, Inc.
-# Copyright (c) 2002 Bryce "Zooko" Wilcox-O'Hearn
+# Copyright (c) 2004 Bryce "Zooko" Wilcox-O'Hearn
# This file is licensed under the
# GNU Lesser General Public License v2.1.
# See the file COPYING or visit http://www.gnu.org/ for details.
@@ -15,39 +15,21 @@ through with their deals in our eyes, et
"""
from cPickle import dumps, loads, UnpicklingError
-import os
-import threading
-import time
-import traceback
-import types
-import math
+import os, threading, time, traceback, types, math
-from pyutil import DoQ
-from pyutil.compat import setdefault
from pyutil.debugprint import debugprint
-from pyutil import Cache
from pyutil.humanreadable import hr
from pyutil import fileutil
-try:
- from bsddb3 import db, dbobj
- db.DB_AUTO_COMMIT = 0
-except:
- from bsddb import db, dbobj
+from egtp import mojoutil
-from egtp.CleanLogDb import CleanLogDbEnv
-from egtp import idlib, mojoutil, mojosixbit
+from base32 import base32
class Peer:
"""
This just holds the peer's Id and its "phonebookentry".
"""
def __init__(self, peerId, phonebookentry):
- """
- @precondition: peerId must be an id.: idlib.is_id(peerId): "peerId: %s :: %s" % (hr(peerId), hr(type(peerId)),)
- """
- assert idlib.is_id(peerId), "precondition: peerId must be an id." + " -- " + "peerId: %s :: %s" % (hr(peerId), hr(type(peerId)),)
-
self.peerId = peerId
self.phonebookentry = phonebookentry
@@ -55,448 +37,26 @@ class Peer:
return hr(self.peerId)
class CounterpartyObjectKeeper:
- class ExtRes:
- """
- This is for holding things (external resources) that COK needs to
- finalize after COK is killed. (post-mortem finalization)
- """
- def __init__(self, db_env, balances_db):
- self.db_env = db_env
- self.balances_db = balances_db
-
- def __del__(self):
- #debugprint("%s.__del__(); stack[-6:-1]: %s\n", args=(self, traceback.extract_stack()[-6:-1],), v=5, vs="debug")
- if self.balances_db is not None :
- self.balances_db.close()
- self.balances_db = None
- if self.db_env is not None :
- self.db_env.nosyncerror_txn_checkpoint(0)
- self.db_env.close()
- self.db_env = None
-
- def __init__(self, dbparentdir, local_id, recoverdb=True) :
- """
- @precondition: `local_id' must be an id.: idlib.is_sloppy_id(local_id): "local_id: %s" % hr(local_id)
- """
- assert idlib.is_sloppy_id(local_id), "`local_id' must be an id." + " -- " + "local_id: %s" % hr(local_id)
-
- local_id = idlib.canonicalize(local_id, "broker")
-
- db_env = CleanLogDbEnv()
- db_env.set_lk_detect(db.DB_LOCK_DEFAULT) # enable automatic deadlock detection
-
- dbdir = os.path.normpath(os.path.join(dbparentdir, idlib.to_mojosixbit(local_id), "cos"))
- fileutil.make_dirs(dbdir)
-
- self._objcache = Cache.LRUCache(maxsize=64)
-
- if recoverdb:
- recoverflag = db.DB_RECOVER
- else:
- recoverflag = 0
-
- # Note: if we want to do multi-processing access to the counterparties db, then we have to turn this off. Note that turning this flag off causes fatal errors on Win2k. --Zooko 2000-11-15
- privateflag = db.DB_PRIVATE
+ def __init__(self, dbparentdir, nodeId) :
+ self.dbdir = os.path.normpath(os.path.join(dbparentdir, base32.b2a_l(nodeId, 160), "cos"))
+ fileutil.make_dirs(self.dbdir)
- try:
- db_env.open(dbdir, db.DB_CREATE | db.DB_INIT_MPOOL | db.DB_INIT_LOCK | db.DB_THREAD | db.DB_INIT_LOG | db.DB_INIT_TXN | privateflag | recoverflag)
- except db.DBError, dbe:
- # XXX HACK: sometimes trying again after one recover works
- debugprint('Failed to open the database environment the first time, reason: %s\nTrying again...\n', args=(dbe,), vs='CounterpartyObjectKeeper', v=2)
- try:
- db_env.open(dbdir, db.DB_CREATE | db.DB_INIT_MPOOL | db.DB_INIT_LOCK | db.DB_THREAD | db.DB_INIT_LOG | db.DB_INIT_TXN | privateflag | recoverflag | db.DB_RECOVER)
- except db.DBError, dbe:
- debugprint('Failed to open the database environment the second time, reason: %s\nTrying again...\n', args=(dbe,), vs='CounterpartyObjectKeeper', v=2)
- # XXX DOUBLE CHOCOLATEY HACK sometimes trying *again* after one open *without* DB_RECOVER works.
- db_env.open(dbdir, db.DB_CREATE | db.DB_INIT_MPOOL | db.DB_INIT_LOCK | db.DB_THREAD | db.DB_INIT_LOG | db.DB_INIT_TXN | privateflag | recoverflag & (~db.DB_RECOVER))
-
- #robk Oct1 this call here suggests that my hunch about this flag being
- # illegal in init but ok for a set_flags has some weight.
- db_env.set_flags(db.DB_TXN_NOSYNC, True)
-
- balances_db = dbobj.DB(db_env)
- balances_db.open('balances', db.DB_BTREE, db.DB_CREATE | db.DB_THREAD | db.DB_AUTO_COMMIT)
-
- self.extres = CounterpartyObjectKeeper.ExtRes(db_env, balances_db)
-
- self.local_id = local_id
-
- self.__mos_update_lock = threading.Lock() # this lock is used for both of the below values
- self.mos_we_owe_others = 0L
- self.mos_others_owe_us = 0L
+ self.nodeId = nodeId
def get_counterparty_object(self, counterparty_id) :
- """
- @precondition: `counterparty_id' must be a binary id.: idlib.is_binary_id(counterparty_id): "counterparty_id: %s" % hr(counterparty_id)
- """
- assert idlib.is_binary_id(counterparty_id), "precondition: `counterparty_id' must be a binary id." + " -- " + "counterparty_id: %s" % hr(counterparty_id)
-
- if idlib.equal(counterparty_id, self.local_id):
- # we don't try and keep track of mo's or a reputation with ourself
- return SelfCounterpartyObject(counterparty_id, self)
-
- cobj = self._objcache.get(counterparty_id)
- if cobj is None:
- cobj = CounterpartyObject(counterparty_id, self)
- self._objcache.insert(counterparty_id, cobj)
-
- return cobj
-
- def get_total_mojo_offer_balance_adjustment(self) :
- """
- @returns: the total mojo that we owe or are owed after taking
- all of our credits and debits into account.
- [this could make you think you have lots of mojo if others_owe_us
- is large; you probably don't want to use this in a UI...]
- """
- self.__mos_update_lock.acquire()
- try:
- return self.mos_others_owe_us - self.mos_we_owe_others
- finally:
- self.__mos_update_lock.release()
-
- def get_total_mojo_we_owe_others(self) :
- """
- @returns: the total mojo that we owe others
- """
- return self.mos_we_owe_others
-
- def get_total_mojo_others_owe_us(self) :
- """
- @returns: the total mojo that others owe us
- """
- return self.mos_others_owe_us
-
- def update_mos_we_owe_others_total(self, value) :
- """
- Add value to our known total of mojo offers that we owe others.
- Call with a negative value to decrease the total.
- This should only be called by CounterParty objects.
- """
- self.__mos_update_lock.acquire()
- try:
- self.mos_we_owe_others = self.mos_we_owe_others + value
- finally:
- self.__mos_update_lock.release()
-
- def update_mos_others_owe_us_total(self, value) :
- """
- @param value: how much more they owe us now
-
- Add value to our known total of mojo offers that other people owe us.
- Call with a negative value to decrease the total.
- This should only be called by CounterParty objects.
- """
- self.__mos_update_lock.acquire()
- try:
- self.mos_others_owe_us = self.mos_others_owe_us + value
- finally:
- self.__mos_update_lock.release()
-
-
-# Greg's NOTES:
-# Store local reputations for each counterparty as:
-# ("number of mojo offers made to counterparty", "related responses received from counterparty")
-#
-# The difference or ratio can be used to determine if we want to deal
-# with a given counterparty again.
-
-# CounterpartyObject database entries are stored keyed on counterparty ids as a pickled dict
+ return CounterpartyObject(self.dbdir, counterparty_id)
class CounterpartyObject:
- """
- Individual counterparty objects are NOT threadsafe
- """
- class ExtRes:
- """
- This is for holding things (external resources) that CO needs to
- finalize after CO is killed. (post-mortem finalization)
- """
- def __init__(self):
- pass
- #def __del__(self):
- # debugprint("%s.__del__(); stack[-6:-1]: %s\n", args=(self, traceback.extract_stack()[-6:-1],), v=5, vs="debug")
-
- def __init__(self, counterparty_id, keeper) :
- """
- @precondition: `counterparty_id' must be an id.: idlib.is_sloppy_id(counterparty_id): "counterparty_id: %s" % hr(counterparty_id)
- """
- assert idlib.is_sloppy_id(counterparty_id), "`counterparty_id' must be an id." + " -- " + "counterparty_id: %s" % hr(counterparty_id)
-
- #debugprint("%s.__init_(); stack[-6:-1]: %s\n", args=(self, traceback.extract_stack()[-6:-1],), v=5, vs="debug")
-
- self.extres = CounterpartyObject.ExtRes()
-
- counterparty_id = idlib.canonicalize(counterparty_id, "broker")
-
- # amount_will_front: this is the maximum amount that she can owe me before I will refuse to loan her more or perform service for her
- # total_spent: this is the total value in Mojo of services I have ever ordered from her
- # total_performed: this is the total value in Mojo of all services I have ever performed for her
- # balance_transferred_in: the current balance i.e. the difference between the aggregate value in Tokens that I've ever given to her and the aggregate value in Tokens that she's ever given to me; positive means she has given me more Mojo than I have given her
- # num_offers_made: the total number of mojo offers that we have ever sent to her
- # num_offers_good: the total number of request that we have ever sent to her, which were accompanied by mojo offers, and which were satisfied by her
-
+ def __init__(self, dbdir, counterparty_id):
self._counterparty_id = counterparty_id
- self.keeper = keeper
- self.trans = None
-
- # tweakable attribs
- self.min_response_reliability_fraction = 0.70
- self.min_num_mo_difference_for_reliability_check = 10
- self.max_num_mo_difference_before_unreliable = 2000
-
- self._tempawfdelta = 0 # This is used to give a cp a temporary increase which is never written to the persistent db. (For fast deposits.)
-
- self._load_from_db()
- # debugprint("xxx %s.__init__() stack[-5:-1]: %s\n", args=(self, traceback.extract_stack()[-5:-1],))
+ self.vals={}
def __repr__(self):
return "<%s:%s, %x>" % (self.__class__.__name__, hr(self._counterparty_id), id(self),)
- def _debugprint(self, str, reasonstr="", args=(), v=1, vs="counterparty"):
- theseargs=[self._counterparty_id]
- theseargs.extend(list(args))
- if reasonstr:
- reasonstr = " [reason: " + reasonstr + "]"
- debugprint("accounting with %s: " + str + reasonstr + "\n", args=theseargs, v=v, vs=vs)
-
- def _load_from_db(self) :
- """called internally to init the internal variables from the database"""
- try:
- stored = self.keeper.extres.balances_db.get(self._counterparty_id)
- except db.DBError, le:
- debugprint("Got error from counterparties db. Initializing counterparty history to defaults. counterparty_id: %s, txn: %s, dbflags: %s, le: %s\n", args=(self._counterparty_id, txn, dbflags, le,), v=0, vs="warning")
- stored = None
-
- if stored is None :
- dict = {}
- else:
- try:
- dict = loads(stored)
- except (UnpicklingError, ValueError,), le:
- debugprint("Got error loading counterparties db. ignoring: %s\n", args=(le,), v=0, vs="warning")
- dict = {}
-
- # Set _every_ counterparty's AWF to 0.
- # This changes an old tradition of keeping the AWF separate for each counterparty.
- # (All of this accounting stuff is on Code Death Row.) --Zooko 2002-11-22
- dict['amount will front'] = 0
- if dict.get('total spent') is None :
- dict['total spent'] = 0
- if dict.get('total performed') is None :
- dict['total performed'] = 0
- if dict.get('balance transferred in') is None :
- dict['balance transferred in'] = 0
- if dict.get('num offers made') is None :
- dict['num offers made'] = 0
- if dict.get('num offers good') is None :
- dict['num offers good'] = 0
-
- self.vals = dict
-
- def synch(self) :
- assert hasattr(self, 'trans') and (self.trans is None), 'should only call synch once per transaction self: %s, self.__dict__: %s' % (hr(self), hr(self.__dict__))
- self.keeper.extres.db_env.nosyncerror_txn_checkpoint(10)
- self.trans = self.keeper.extres.db_env.txn_begin()
- # debugprint("xxx %s.synch() stack[-5:-1]: %s\n", args=(self, traceback.extract_stack()[-5:-1],))
-
- def save(self, checkpoint=False) :
- assert self.trans is not None, 'should only call save() once'
-
- newval = dumps(self.vals)
- try:
- self.keeper.extres.balances_db.put(self._counterparty_id, newval, txn=self.trans)
- except db.DBError, le:
- debugprint("Got error from counterparties db trying to save. Ignoring. counterparty_id: %s, vals: %s, le: %s\n", args=(self._counterparty_id, self.vals, le,), v=0, vs="warning")
-
- self.trans.commit()
- self.trans = None
- if checkpoint:
- # since we're using DB_TXN_NOSYNC we allow checkpoints to be
- # forced at important times such as when recording an actual
- # token going in our out.
- self.keeper.extres.db_env.nosyncerror_txn_checkpoint(0)
-
- def done(self) :
- if self.trans is not None :
- self.trans.abort()
- self.trans = None
-
- def charge(self, amount, reasonstr="") :
- """
- @precondition: `amount' is an integer.: type(amount) == types.IntType or type(amount) == types.LongType: "amount: %s :: %s" % (hr(amount), str(type(amount)))
- @precondition: `amount' is non-negative.: amount >= 0: "amount: %s" % hr(amount)
-
- @returns: tuple: (okay, amount will front, current balance)
- """
- assert type(amount) == types.IntType or type(amount) == types.LongType, "`amount' is an integer." + " -- " + "amount: %s :: %s" % (hr(amount), str(type(amount)))
- assert amount >= 0, "`amount' is non-negative." + " -- " + "amount: %s" % hr(amount)
-
- self.synch()
- try :
- # This is the amount that you owe me.
- cur_balance = long(self.vals['total performed'] - self.vals['total spent'] - self.vals['balance transferred in'])
- new_balance = long(cur_balance + amount)
- amtwfront = long(self.vals['amount will front']) + self._tempawfdelta
-
- self._debugprint("counterparties.charge(): amtwfront: %s, self._tempawfdelta: %s\n", args=(amtwfront, self._tempawfdelta,), v=7, vs="accounting")
-
- # As a special case, it is always ok to charge 0.
- if amount == 0:
- self._debugprint("extending %s credit to her; new_balance = %s", args=(amount, new_balance,), reasonstr=reasonstr)
- return True, amtwfront, new_balance
-
- self.keeper.update_mos_others_owe_us_total(amount) # they owe us more
- self._debugprint("extending %s credit to her. new_balance = %s", args=(amount, new_balance,), reasonstr=reasonstr)
- self.vals['total performed'] = self.vals['total performed'] + amount
- self.save()
- return True, amtwfront, new_balance
- finally :
- self.done()
-
def get_counterparty_id(self) :
return self._counterparty_id
- def spend(self, amount, reasonstr="") :
- """
- increment our record of total_spent and our num_offers_made
-
- @precondition: `amount' is an integer.: type(amount) == types.IntType or type(amount) == types.LongType: "amount: %s :: %s" % (hr(amount), str(type(amount)))
- @precondition: `amount' is non-negative.: amount >= 0: "amount: %s" % hr(amount)
- """
- assert type(amount) == types.IntType or type(amount) == types.LongType, "`amount' is an integer." + " -- " + "amount: %s :: %s" % (hr(amount), str(type(amount)))
- assert amount >= 0, "`amount' is non-negative." + " -- " + "amount: %s" % hr(amount)
-
- self.synch()
- try:
- prevtotalspent = self.vals['total spent']
- newtotalspent = prevtotalspent + amount
- self.vals['total spent'] = newtotalspent
- self.keeper.update_mos_we_owe_others_total(amount) # we owe them more
- self.vals['num offers made'] = self.vals['num offers made'] + 1
- self._debugprint("requesting %s credit from her; total_spent with her = %s" % (amount, self.vals['total spent']), reasonstr=reasonstr)
-
- self.save()
- finally :
- self.done()
-
- def unspend(self, amount, reasonstr="") :
- """
- Only call this if you KNOW that your message was never sent (otherwise will torture your loved ones)
-
- @precondition: `amount' is an integer.: type(amount) == types.IntType or type(amount) == types.LongType: "amount: %s :: %s" % (hr(amount), str(type(amount)))
- @precondition: `amount' is non-negative.: amount >= 0: "amount: %s" % hr(amount)
- """
- assert type(amount) == types.IntType or type(amount) == types.LongType, "`amount' is an integer." + " -- " + "amount: %s :: %s" % (hr(amount), str(type(amount)))
- assert amount >= 0, "`amount' is non-negative." + " -- " + "amount: %s" % hr(amount)
-
- self.synch()
- try :
- self.vals['total spent'] = self.vals['total spent'] - amount
- self.keeper.update_mos_we_owe_others_total(0L - amount) # whoops, take that back!
-
- # never allow total spent to go negative, that's "weird"; if we unspend() that much, start
- # marking it as services performed for the counterparty and them owing us more.
- if self.vals['total spent'] < 0:
- amount_performed = 0L - self.vals['total spent']
- self.vals['total spent'] = 0L
- self.vals['total performed'] = self.vals['total performed'] + amount_performed
- self.keeper.update_mos_we_owe_others_total(amount_performed)
- self.keeper.update_mos_others_owe_us_total(amount_performed)
-
- self._debugprint("taking back request for %s credit from her; total_spent (with her) = %s" % (amount, self.vals['total spent']), reasonstr=reasonstr, v=3)
- self.save()
- finally :
- self.done()
-
- def token_payment_came_in(self, amount, reasonstr=""):
- """
- @param amount: the aggregate value in Mojo of the payment
-
- @precondition: `amount' is an integer.: type(amount) == types.IntType or type(amount) == types.LongType: "amount: %s :: %s" % (hr(amount), str(type(amount)))
- @precondition: `amount' is positive.: amount > 0: "amount: %s" % hr(amount)
- """
- assert type(amount) == types.IntType or type(amount) == types.LongType, "`amount' is an integer." + " -- " + "amount: %s :: %s" % (hr(amount), str(type(amount)))
- assert amount > 0, "`amount' is positive." + " -- " + "amount: %s" % hr(amount)
-
- self.synch()
- try :
- self.vals['balance transferred in'] = self.vals['balance transferred in'] + amount
- self.keeper.update_mos_others_owe_us_total(0L - amount) # they paid up, now they owe us less
- self._debugprint("received tokens worth %s from her; balance_transferred_in (with her) = %s" % (amount, self.vals['balance transferred in']), reasonstr=reasonstr)
- self.save(checkpoint=True)
- finally :
- self.done()
-
- def token_payment_went_out(self, amount, reasonstr=""):
- """
- @param amount: the aggregate value in Mojo of the payment
-
- @precondition: `amount' is an integer.: type(amount) == types.IntType or type(amount) == types.LongType: "amount: %s :: %s" % (hr(amount), str(type(amount)))
- @precondition: `amount' is positive.: amount > 0: "amount: %s" % hr(amount)
- """
- assert type(amount) == types.IntType or type(amount) == types.LongType, "`amount' is an integer." + " -- " + "amount: %s :: %s" % (hr(amount), str(type(amount)))
- assert amount > 0, "`amount' is positive." + " -- " + "amount: %s" % hr(amount)
-
- self.synch()
- try :
- self.vals['balance transferred in'] = self.vals['balance transferred in'] - amount
- self.keeper.update_mos_we_owe_others_total(0L - amount) # we paid up, now we owe less
- self._debugprint("spent tokens worth %s to her; balance_transferred_in (with her) = %s" % (amount, self.vals['balance transferred in']), reasonstr=reasonstr)
- self.save(checkpoint=True)
- finally :
- self.done()
-
- def record_spend_success(self) :
- """
- Increment our num_offers_good counter.
- Call this once we've receive a valid response to a MO message we sent earlier
- """
- self.synch()
- try:
- self.vals['num offers good'] = self.vals['num offers good'] + 1
- self.save()
- finally:
- self.done()
-
- def increment_reliability(self):
- self.update_custom_stat_weighted_sample('reliability', 1)
- def decrement_reliability(self):
- self.update_custom_stat_weighted_sample('reliability', 0)
-
-
- def update_custom_stat(self, statname, updatefunc, initialvalue):
- """
- Update a custom counterparty reputation statistic with the return value of updatefunc(currentstat).
- The updatefunc is called while holding the counterparty's transaction lock so it needs to be fast.
- (if the statistic doesn't yet exist, initialvalue will be passed to updatefunc).
- """
- self.synch()
- try:
- self.vals[statname] = updatefunc( self.vals.get(statname, initialvalue) )
- self.save()
- finally:
- self.done()
-
- def update_custom_stat_weighted_sample(self, statname, newvalue, historyweight=None, defaultvalue=0.5):
- """
- @param historyweight: 0.0 = ignore history, 1.0 = ignore new sample
- """
- if historyweight is None:
- historyweight = 0.75
- assert (historyweight >= 0) and (historyweight <= 1), "a 0.0 <= historyweight <= 1.0 is required"
- self.synch()
- try:
- stat = self.vals.get(statname)
- if stat is None:
- stat = float(defaultvalue)
- stat = (historyweight * stat) + ((1.0 - historyweight)*newvalue)
- self.vals[statname] = float(stat)
- self.save()
- return float(stat)
- finally:
- self.done()
-
def update_custom_stat_weighted_sample_with_deviation(self, statname, newvalue, historyweight=None):
"""
@param historyweight: 0.0 = ignore history, 1.0 = ignore new sample
@@ -504,39 +64,10 @@ class CounterpartyObject:
if historyweight is None:
historyweight = 0.75
assert (historyweight >= 0) and (historyweight <= 1), "a 0.0 <= historyweight <= 1.0 is required"
- self.synch()
- try:
- stat = self.vals.get(statname)
- self.vals[statname] = mojoutil.update_weighted_sample(stat, newvalue, historyweight)
- self.save()
- return self.vals[statname]
- finally:
- self.done()
+ stat = self.vals.get(statname)
+ self.vals[statname] = mojoutil.update_weighted_sample(stat, newvalue, historyweight)
+ return self.vals[statname]
- def update_custom_stat_list(self, statname, newitem, maxlen) :
- """
- Update a custom counterparty reputation stored as a list of statistics. Append newitem to the list
- and make sure the list is not longer than maxlen items long. This uses update_custom_stat() and is
- a convenience interface as lists of stats are kept quite often.
- If no stat-list of the given name exists, a new one will be created.
- """
- def add_to_list(self, currentlist, newitem=newitem, maxlen=maxlen):
- currentlist.append(newitem)
- currentlist = currentlist[:maxlen]
- return currentlist
- self.update_custom_stat(statname, updatefunc=add_to_list, initialvalue=[])
-
- def delete_custom_stat(self, statname):
- """remove a counterparty statistic (useful for removing old no longer used ones)"""
- if self.vals.has_key(statname):
- self.synch()
- try:
- if self.vals.has_key(statname): # this could have changed after the synch()
- del self.vals[statname]
- self.save()
- finally:
- self.done()
-
def get_custom_stat(self, statname, default=None) :
"""
Return a custom counterparty reputation statistic.
@@ -544,121 +75,3 @@ class CounterpartyObject:
"""
return self.vals.get(statname, default)
- def set_reliability(self, reliability):
- self.synch()
- try:
- self.vals['reliability'] = float(reliability)
- self.save()
- return self.vals['reliability']
- finally:
- self.done()
-
- def is_unreliable(self) :
- # Make sure we're up to date w/ whats on the disk
- self.synch()
- try:
- num_made = self.vals['num offers made']
- num_good = self.vals['num offers good']
- assert num_made >= 0 and num_good >= 0
- if num_good > num_made :
- self._debugprint("WARNING: mojo_offers_good is greater than mojo_offers_made. fixing.")
- num_good = num_made
- self.save()
- return 0
- if num_made == num_good :
- # reminder: this also takes care of when they are both zero
- # (we're friendly by default, trusting strangers until they flake on us)
- return 0
- else :
- reliability_percent = float(num_good) / num_made
- size_of_disagreement = num_made - num_good
- if reliability_percent < self.min_response_reliability_fraction and size_of_disagreement >= self.min_num_mo_difference_for_reliability_check :
- return 1 # they're currently unreliable
- if size_of_disagreement >= self.max_num_mo_difference_before_unreliable:
- return 1 # they're currently unreliable
- return 0
- finally:
- self.done()
-
- def get_amount_will_front(self) :
- self.synch()
- try :
- # Note: not adding self._tempawfdelta here, because this is only called currently in order to determine if _you_ will front _her_ a coin...
- return self.vals['amount will front']
- finally :
- self.done()
-
- def raise_temp_awf(self, raiseby):
- self._tempawfdelta = self._tempawfdelta + raiseby
-
- def lower_temp_awf(self, raiseby):
- self._tempawfdelta = max(self._tempawfdelta - raiseby, 0)
-
- def get_amount_owe(self) :
- """
- @return: the amount of Mojo that I owe to her
- """
- self.synch()
- try :
- return self.vals['total spent'] - self.vals['total performed'] + self.vals['balance transferred in']
- finally :
- self.done()
-
- def get_balance_transferred_in(self) :
- """
- @return: the value of all Mojo Token that she has given me; Negative if I have given her more tokens than she has given me.
- """
- self.synch()
- try :
- return self.vals['balance transferred in']
- finally :
- self.done()
-
-
- # called whenever account balance changes to notify
- # any relevant callbacks
- def __new_balance(self) :
- pass
-
-
-
-
-class SelfCounterpartyObject(CounterpartyObject):
- """Used as the counterparty for ourselves. It does nothing.
- We like ourself so much that we don't bother to pay ourself.
- """
- def __init__(self, counterparty_id, keeper) :
- self._counterparty_id = counterparty_id
- self.keeper = keeper
- self.trans = None
- self._tempawfdelta = 0 # This is used to give a cp a temporary increase which is never written to the persistent db. (For fast deposits.)
- def charge(self, amount, reasonstr="") :
- return True, 1000000000, 0
- def spend(self, amount, reasonstr="") :
- pass
- def unspend(self, amount, reasonstr="") :
- pass
- def record_spend_success(self) :
- pass
- def is_unreliable(self) :
- return 0
- def get_amount_will_front(self) :
- return 10000000000L
- def get_amount_owe(self) :
- return 0
- def token_payment_came_in(self, amount, reasonstr=""):
- return
- def token_payment_went_out(self, amount, reasonstr=""):
- return
- def update_custom_stat(self, statname, updatefunc, initialvalue) :
- updatefunc(initialvalue)
- return
- def update_custom_stat_weighted_sample(self, statname, newvalue, historyweight=None):
- return
- def update_custom_stat_weighted_sample_with_deviation(self, statname, newvalue, historyweight=None):
- return
- def update_custom_stat_list(self, statname, newitem, maxlen) :
- return
- def get_custom_stat(self, statname, default = None) :
- return default
-
Index: mnetlib/filesystem/blockwrangler.py
===================================================================
RCS file: /cvsroot/mnet/mnet_new/mnetlib/filesystem/blockwrangler.py,v
retrieving revision 1.27
diff -p -u -r1.27 blockwrangler.py
--- mnetlib/filesystem/blockwrangler.py 13 Feb 2004 22:02:01 -0000 1.27
+++ mnetlib/filesystem/blockwrangler.py 6 Apr 2004 16:00:48 -0000
@@ -212,8 +212,6 @@ class BlockWrangler(nummedobj.NummedObj)
self.handle_successful_look_for_blocks_result(outcome, failure_reason, queryblockIds, peer)
else:
- # Inform reliability handicapper that this was actually a failure.
- self.node.mtm._keeper.get_counterparty_object(peer.peerId).decrement_reliability()
self.data.remove_Ids_of_located_blocks(peer, blockIds=queryblockIds)
# Tell the strategy to wake up -- there are new results to consider! (Even failure is a new result to consider.)
@@ -304,10 +302,6 @@ class BlockWrangler(nummedobj.NummedObj)
assert self.numoutstandingrequestswithpeer.get(peer, 0) >= 0
if failure_reason:
- # Inform reliability handicapper that this was actually a
- # failure.
-
- self.node.mtm._keeper.get_counterparty_object(peer.peerId).decrement_reliability()
# Wake the block wrangling strategy -- failure to retrieve a
# block is the kind of thing that it might want to respond
# to.
More information about the Mnet-devel
mailing list