[sqlalchemy] Re: Concurrency problem with SA 0.4

2007-10-22 Thread Michael Bayer


On Oct 22, 2007, at 4:25 AM, alain D. wrote:


  Obj is a simple python object with on field (key : String(10)) mapped
 to a table with on field (key) with is the primary key.
 Session is defined like this :
 engine = create_engine(**mysql_string**, strategy='threadlocal',
 pool_size=50)
 Session = scoped_session(sessionmaker(bind=engine, autoflush=True,
 transactional=True))

   If I launch 2 python shells :
   In the first I do :
 sess = Session()
 obj = Obj(first_key)
 sess.save()
 sess.commit()

   In the second I do
 sess = Session() #this is done at the same time than the creation in
 the first shell
 # wait after commit in shell 1
 oo = sess.query(Obj).filter_by(key=first_key).first
 # oo is None


its likely that a transaction is begun in the second session before  
the first session commits - transaction isolation will prevent #2  
from seeing new changes until its either rolled back or committed.

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~--~~~~--~~--~--~---



[sqlalchemy] Re: Concurrency problem with SA 0.4

2007-10-22 Thread alain D.

I forgot to say that I use mysql with InnoDB backend
(autoflush=True,transactional=True)



--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~--~~~~--~~--~--~---



[sqlalchemy] Re: Concurrency problem with SA 0.4

2007-10-22 Thread Michael Bayer


On Oct 22, 2007, at 1:43 PM, alain D. wrote:


 thanks a lot for you reply ...

 If I understand correctly, a simple sess.begin() in #2 executed
 right after the #1 commit will work (?). But I tested it and I still
 dont get the commited object ...
 What am I missing

no, a sess.rollback() or sess.commit() in #2.  sess.begin() wont do  
anything here.



--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~--~~~~--~~--~--~---



[sqlalchemy] Re: Concurrency problem

2007-04-03 Thread Michael Bayer


On Apr 2, 2007, at 10:35 PM, Barry Warsaw wrote:


 -BEGIN PGP SIGNED MESSAGE-
 Hash: SHA1

 Our populate_instance() checks the isnew flag and if this is true, it
 does not call our initialization stuff.  Now, I don't really see the
 isnew flag documented, so I assumed it was only called when the
 object was initially loaded from the database, but apparently it's
 true /every/ time the object is loaded.  So when I session.expire()
 it and then subsequently load it, populate_instance() gets called
 with isnew=True.  The causes our application-specific initialization
 stuff to get called on an existing MailList object, and this is what
 blows away our lock attribute.

 I guess that if the documentation for isnew in append_result() is the
 same as isnew in populate_instance() then indeed we'll need that
 extra check.  Is that correct?


OK, yes, im sorry about the lack of docs for isnew...sometimes i  
subconsciously want to see how long it takes for someone to ask me  
about something (bad habit) although in this case that flag is over a  
year old and i think youre the first :)

isnew is used to indicate that we are going to populate the  
instance with data from the database, *and* that this particular row  
is the first row in the result which has indicated the presence of  
this entity (i.e. the primary key points to it).   this implies that  
populate_instance() can be called *multiple times* for the instance,  
if multiple successive rows all contain its particular primary key.
this is how SA deals with the products of eager loads and other  
joins, where many rows contain the same entity identity in a number  
of successive rows corresponding to the total product of eagerly  
loaded child items - the normal populate_instance() just delegates  
the populate this attribute task onto MapperProperty objects that  
represent each attribute. for the MapperProperty objects that  
represent eager loaders, they unconditionally send the row off to  
their child mappers to look at the row, where it then goes into its  
own populate_instance() process with a possibly True isnew flag.

so basically, isnew means populate attributes and if its false it  
means we already did this entity.




--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~--~~~~--~~--~--~---



[sqlalchemy] Re: Concurrency problem

2007-04-03 Thread Barry Warsaw

-BEGIN PGP SIGNED MESSAGE-
Hash: SHA1

On Apr 3, 2007, at 9:35 AM, Michael Bayer wrote:

 OK, yes, im sorry about the lack of docs for isnew...sometimes i
 subconsciously want to see how long it takes for someone to ask me
 about something (bad habit) although in this case that flag is over a
 year old and i think youre the first :)

Heh, um glad to help? :)

 so basically, isnew means populate attributes and if its false it
 means we already did this entity.

Cool, thanks.  That tells me what I need to know!

- -Barry

-BEGIN PGP SIGNATURE-
Version: GnuPG v1.4.5 (Darwin)

iQCVAwUBRhKhIXEjvBPtnXfVAQIJAAP/XRTViMrga4tOECEJD0OkacjfcUCVQOV3
lDUTPtu09se0uiPlZvfW03w7BBniguupLFSUOPBQHlf/Zh3SWG585lF9HeNP0ocC
viBepxS+2rm1Y3CZVnXvfNwZYUfpn1vwns2+cOFoHnwR8scdexK9UTAG7yIH/ICs
IzNwbKB/g7U=
=bDwL
-END PGP SIGNATURE-

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~--~~~~--~~--~--~---



[sqlalchemy] Re: Concurrency problem

2007-04-02 Thread Michael Bayer


On Apr 2, 2007, at 1:46 PM, Barry Warsaw wrote:


 The problem is that if we call session.expire(mlist) /after/ the
 MailList.__lock attribute gets set, it appears as though SA 'messes'
 with this attribute.  I've proven that if the session.expire() gets
 called after MailList.Lock(), during the .Load() we lose our lock,
 but if we call session.expire() before we're locked, everything's
 fine.  I'm not 100% sure yet why that happens, but it does appear to
 be a strange interaction between SA's identity map and non-SA
 controlled attributes.


I cant think of any reason why SA would be touching object attributes  
which are not part of a mapping.  can you be more specific about how  
this object is mapped and in what way is it related to other  
objects ?  (i.e. are you sure its the *same* instance of MailList ?   
thats the only reason i could think that its a different __lock  
attribute).

also, why dont you just use the load() method on Query to load the  
object ?  this will overwrite all attributes of the instance with  
that loaded from the database; expire() would not be needed.

 So, I'm looking for some advice on how to handle synchronization
 between processes in a situation like this.  Ultimately I think I'd
 like to use mapper's always_refresh, but maybe that's not the right
 thing.

the always_refresh flag was added at the extremely vocal requests of  
a single user who refused to accept the concepts of identity map and  
unit of work.  I cant make any recommendations how such a flag should  
be used.  the load() operation should be a more controllable way to  
handle loading.

 The related issue is that MailList's may have other ORM
 objects hanging off of it and they'd all need to be re-sync'd with
 the database at the same time.  Our MailList objects hang around for
 a long time, and so we already have the resync locations coded
 (essentially MailList.Load() calls).  Those are the points where we'd
 like to expire our in-memory objects, though we can't lose the state
 of our non-SA controlled attributes.

heres the big catch - the objects that you place in your Session are  
generally not going to respond well to concurrent access, since the  
Session itself is not threadsafe nor are the attribute-level  
operations performed on instances.   You might want to look into  
separating the database-related state of MailList into an entity that  
is useable on a more ad-hoc basis, so that MailList, its lock  
attributes, and its synchronization needs arent impacted by SA  
session semantics which are intended to be single-thread operations.   
alternatively, you can try having your long-lived MailList living  
outside of the session, and to merge() it into a session when you  
need to do flushes (merge does not impact the original instance, but  
rather creates a copy of the instance within the session).

the feeling im getting here, without seeing how you have things set  
up, is that youre hanging a lot of functionality off a single type of  
object (locking, persistence, etc), and perhaps this is where a  
greater notion of separation of concerns might be helpful.




--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~--~~~~--~~--~--~---