Re: [ZODB-Dev] zodb conversion questions

2013-02-14 Thread Jürgen Herrmann

Am 07.02.2013 17:11, schrieb Jim Fulton:

On Thu, Feb 7, 2013 at 10:48 AM, Jürgen Herrmann
juergen.herrm...@xlhost.de wrote:

Am 06.02.2013 15:05, schrieb Jürgen Herrmann:


Hi there!

I hav a relstorage with mysql backend that grew out of bounds
and we're looking into different backend solutions now. Possibly
also going back to FileStorage and using zeo...

Anyway we'll have to convert the databases at some point. As these
are live DBs we cannot shut them down for longer than the
ususal maintenance interval during the night, so for maybe 2-3h.

a full conversion process will never complete in this time so
we're looking for a process that can split the conversion into
two phases:

1. copy transactions from backup of the source db to the 
destination

   db. this can take a long time, we don't care. note the last
   timestamp/transaction_id converted.
2. shut down the source db
3. copy transactions from the source db to the destination db, 
starting
   at the last converted transaction_id. this should be fast, as 
only

   a few transactions need to be converted, say  1% .


if i would reimplement copyTransactionsFrom() to accept a start
transaction_id/timestamp, would this result in dest being an exact
copy of source?

source = open_my_source_storage()
dest = open_my_destination_storage()
dest.copyTransactionsFrom(source)
last_txn_id = source.lastTransaction()
source.close()
dest.close()

source = open_my_source_storage()
# add some transactions
source.close()

source = open_my_source_storage()
dest = open_my_destination_storage()
dest.copyTransactionsFrom(source, last_txn_id=last_txn_id)
source.close()
dest.close()



I will reply to myself here :) This actually works, tested with a
modified version of FileStorage for now. I modified the signature
of copyTransactionsFrom to look like this:

def copyTransactionsFrom(self, source, verbose=0, 
not_before_tid=None):


``start`` would be better to be consistent with the iterator API.


not_before_tid is a packed tid or None, None meaning copy all
(the default, so no existing API usage would break).

Is there public interest in modifying this API permamently?


+.1

This API is a bit of an attractive nuisance.  I'd rather people
learn how to use iterators in their own scripts, as they are very
useful and powerful.  This API just hides that.

The second part, replaying old transactions is a bit more subtle,
but it's still worth it for people to be aware of it.

If I were doing this today, I'd make this documentation
rather than API. But then, documentation ... whimper.


Anybody want to look at the actual code changes?


Sure, if they have tests.  Unfortunately, we can only accept
pull requests from zope contributors. Are you one?
Wanna be one? :)

Jim


1. SUCCESS. I migrated to FileStorage/ZEO successfully with the 
modified
   copyTransactionsFrom() with downtime of only 10 minutes. Very cool 
:)
   DB sizes are reasonable again and repozo backups are set up, just 
like
   before the migration to RelStorage. Feels robust again, a good 
feeling.

   I'd advise anybody thinking about migrating to RelStorage to think
   about a proper (incremental) backup strategy for the underlying sql 
db

   first, this might become crucial! repozo makes your life easy there
   when using FileStorage.

2. Regarding the tests: I did not find any test for 
copyTransactionsFrom()

   in the current test suite, am I blind? If there isn't any test yet,
   maybe you could suggest a proper file for the test, maybe even a 
similar

   one to start from?

3. Regarding my request to have this in ZODB 3.10.5:
   After reading my own statement I quickly realized that changing an 
API
   can only happen in a major version. Anyway, this was a one-shot 
action

   so I'll probably never need my own code again :)

best regards,
Jürgen
--

XLhost.de ® - Webhosting von supersmall bis eXtra Large 


XLhost.de GmbH
Jürgen Herrmann, Geschäftsführer
Boelckestrasse 21, 93051 Regensburg, Germany

Geschäftsführer: Jürgen Herrmann
Registriert unter: HRB9918
Umsatzsteuer-Identifikationsnummer: DE245931218

Fon:  +49 (0)800 XLHOSTDE [0800 95467833]
Fax:  +49 (0)800 95467830
Web:  http://www.XLhost.de
___
For more information about ZODB, see http://zodb.org/

ZODB-Dev mailing list  -  ZODB-Dev@zope.org
https://mail.zope.org/mailman/listinfo/zodb-dev


Re: [ZODB-Dev] zodb conversion questions

2013-02-14 Thread Ruda Porto Filgueiras
Hi,

Will be cool if you create a package with this script and with instructions
to patch ZODB and maybe new major version could have the new API.

If you need help I'm interested to do it. :-)

Cheers,


On Thu, Feb 14, 2013 at 6:29 PM, Jürgen Herrmann juergen.herrm...@xlhost.de
 wrote:

 Am 07.02.2013 17:11, schrieb Jim Fulton:

 On Thu, Feb 7, 2013 at 10:48 AM, Jürgen Herrmann

 juergen.herrm...@xlhost.de wrote:

 Am 06.02.2013 15:05, schrieb Jürgen Herrmann:

  Hi there!

 I hav a relstorage with mysql backend that grew out of bounds
 and we're looking into different backend solutions now. Possibly
 also going back to FileStorage and using zeo...

 Anyway we'll have to convert the databases at some point. As these
 are live DBs we cannot shut them down for longer than the
 ususal maintenance interval during the night, so for maybe 2-3h.

 a full conversion process will never complete in this time so
 we're looking for a process that can split the conversion into
 two phases:

 1. copy transactions from backup of the source db to the destination
db. this can take a long time, we don't care. note the last
timestamp/transaction_id converted.
 2. shut down the source db
 3. copy transactions from the source db to the destination db, starting
at the last converted transaction_id. this should be fast, as only
a few transactions need to be converted, say  1% .


 if i would reimplement copyTransactionsFrom() to accept a start
 transaction_id/timestamp, would this result in dest being an exact
 copy of source?

 source = open_my_source_storage()
 dest = open_my_destination_storage()
 dest.copyTransactionsFrom(**source)
 last_txn_id = source.lastTransaction()
 source.close()
 dest.close()

 source = open_my_source_storage()
 # add some transactions
 source.close()

 source = open_my_source_storage()
 dest = open_my_destination_storage()
 dest.copyTransactionsFrom(**source, last_txn_id=last_txn_id)
 source.close()
 dest.close()



 I will reply to myself here :) This actually works, tested with a
 modified version of FileStorage for now. I modified the signature
 of copyTransactionsFrom to look like this:

 def copyTransactionsFrom(self, source, verbose=0, not_before_tid=None):


 ``start`` would be better to be consistent with the iterator API.

  not_before_tid is a packed tid or None, None meaning copy all
 (the default, so no existing API usage would break).

 Is there public interest in modifying this API permamently?


 +.1

 This API is a bit of an attractive nuisance.  I'd rather people
 learn how to use iterators in their own scripts, as they are very
 useful and powerful.  This API just hides that.

 The second part, replaying old transactions is a bit more subtle,
 but it's still worth it for people to be aware of it.

 If I were doing this today, I'd make this documentation
 rather than API. But then, documentation ... whimper.

  Anybody want to look at the actual code changes?


 Sure, if they have tests.  Unfortunately, we can only accept
 pull requests from zope contributors. Are you one?
 Wanna be one? :)

 Jim


 1. SUCCESS. I migrated to FileStorage/ZEO successfully with the modified
copyTransactionsFrom() with downtime of only 10 minutes. Very cool :)
DB sizes are reasonable again and repozo backups are set up, just like
before the migration to RelStorage. Feels robust again, a good feeling.
I'd advise anybody thinking about migrating to RelStorage to think
about a proper (incremental) backup strategy for the underlying sql db
first, this might become crucial! repozo makes your life easy there
when using FileStorage.

 2. Regarding the tests: I did not find any test for copyTransactionsFrom()
in the current test suite, am I blind? If there isn't any test yet,
maybe you could suggest a proper file for the test, maybe even a similar
one to start from?

 3. Regarding my request to have this in ZODB 3.10.5:
After reading my own statement I quickly realized that changing an API
can only happen in a major version. Anyway, this was a one-shot action
so I'll probably never need my own code again :)

 best regards,
 Jürgen

 --

 XLhost.de ® - Webhosting von supersmall bis eXtra Large 


 XLhost.de GmbH
 Jürgen Herrmann, Geschäftsführer
 Boelckestrasse 21, 93051 Regensburg, Germany

 Geschäftsführer: Jürgen Herrmann
 Registriert unter: HRB9918
 Umsatzsteuer-**Identifikationsnummer: DE245931218

 Fon:  +49 (0)800 XLHOSTDE [0800 95467833]
 Fax:  +49 (0)800 95467830
 Web:  http://www.XLhost.de
 __**_
 For more information about ZODB, see http://zodb.org/

 ZODB-Dev mailing list  -  ZODB-Dev@zope.org
 https://mail.zope.org/mailman/**listinfo/zodb-devhttps://mail.zope.org/mailman/listinfo/zodb-dev




-- 
Rudá Porto Filgueiras
http://python-blog.blogspot.com
http://twitter.com/rudaporto
___
For more information about ZODB, see http://zodb.org/


[ZODB-Dev] A certain code path seems to be blocking everything

2013-02-14 Thread Claudiu Saftoiu
I've got a weird bug with my server and I'm wondering if anyone could
provide some insight
into it.

The general idea of the server is that I have 8 or so clients constantly
pinging it for information.
Each ping usually only takes up to 2 seconds to process.

Essentially, everything runs fine, until a certain code path is executed -
basically, one of
the clients causes the server to try to give it some other information than
usual. When this
client is turned on and starts pinging the server, suddenly all those
requests that only took
0.5-2 seconds now take 10, 20, or even 30 seconds.

I'm using paster and using its thread-tracker tool I can see what all the
threads are doing at
any given point. Usually there's anywhere from 0 to 4 requests going on,
each having taken
less than 1 second up to that point. When the 'special client' is turned
on, there's more like
10 requests each having taken 6 seconds or more up to that point. There
aren't more
requests, it's just that they don't clear out quickly enough. The tail end
of the tracebacks
are one of two things:

  File /home/tsa/env/lib/python2.6/site-packages/transaction/_manager.py,
line 89, in commit
return self.get().commit()
  File /home/tsa/env/lib/python2.6/site-packages/transaction/_transaction.py,
line 329, in commit
self._commitResources()
  File /home/tsa/env/lib/python2.6/site-packages/transaction/_transaction.py,
line 441, in _commitResources
rm.tpc_begin(self)
  File /home/tsa/env/lib/python2.6/site-packages/ZODB/Connection.py,
line 547, in tpc_begin
self._normal_storage.tpc_begin(transaction)
  File /home/tsa/env/lib/python2.6/site-packages/ZEO/ClientStorage.py,
line 1118, in tpc_begin
self._tpc_cond.wait(30)
  File /usr/lib/python2.6/threading.py, line 258, in wait
_sleep(delay)

Or:

  File /home/tsa/env/lib/python2.6/site-packages/ZODB/Connection.py,
line 856, in setstate
self._setstate(obj)
  File /home/tsa/env/lib/python2.6/site-packages/ZODB/Connection.py,
line 897, in _setstate
p, serial = self._storage.load(obj._p_oid, '')
  File /home/tsa/env/lib/python2.6/site-packages/ZEO/ClientStorage.py,
line 824, in load
self._load_lock.acquire()

I read through the code a bit and it sees that only one thread can commit
at a time.
So, my first guess is that the 'special' request is taking particularly
long to commit, which
ends up slowing everything else down. Would that be a fair estimation? What
might
cause a commit to take abnormally long? Just looking at the code I can't
see anything
that particularly stands out, especially since this bug only started
happening recently
and I haven't really changed that part of the code on the server-side
recently. I did
refactor the client code but I don't yet see how that might be causing this
issue.

One last thing. I have certain views which touch a lot of different parts
of the database and
do a lot of processing. I had many conflict errors in the past, and
retrying the entire view
all the time proved to be too inefficient, so I separated the code out into
blocks, where
I retry each block separately. This function describes the pattern well:

def commit_and_inner_retry(transaction_manager, func, num_retries,
ingdescription)):
Using the `transaction_manager`:
1) commit the transaction thus far
2) try `num_retries` times to begin a new transaction, execute
`func`, which is
   passed the current transaction as its only argument, and then
commit the
   new transaction. if ConflictError is raised, abort  try again
3) if a failure happens, then an error is printed involving
`ingdescription`
4) raise ConflictError if retrying `num_retries` times does not
work.


tm = transaction_manager
tm.commit()
for retry in range(num_retries):
tm.begin()
return_value = func(tm.get())
try:
tm.commit()
except ConflictError:
print Conflict error attempt #%d %s, trying again %
(retry+1, ingdescription)
tm.abort()
continue
break
else:
raise ConflictError(Was never able to commit %s %
ingdescription)

return return_value

With the view code looking something like this:

def long_view(context, request):
db_objs = prepare_stuff()

def do_stuff_1():
return stuff_1_with_db_objs(db_objs)
stuff1 = commit_and_inner_retry(
transaction.manager, block, 10, 'doing stuff 1')

def do_stuff_2():
return stuff_2_with_db_objs(stuff1)
stuff2 = commit_and_inner_retry(
transaction.manager, block, 10, 'doing stuff 2')

def do_stuff_3():
stuff_3_with_db_objs(stuff2)
try:
commit_and_inner_retry(
transaction.manager, block, 10, 'doing stuff 3')
except ConflictError:
#this stuff not important