Re: [ZODB-Dev] Increasing MAX_BUCKET_SIZE for IISet, etc

2011-01-27 Thread Tres Seaver
-BEGIN PGP SIGNED MESSAGE-
Hash: SHA1

On 01/27/2011 05:09 AM, Matt Hamilton wrote:

>> Conflicts inside the same bucket can be resolved and you won't get to
>> see any log message for them. If you get a ConflictError in the logs,
>> it's one where the request is being retried.
> 
> Great. That was that I always thought, but just wanted to check. So in
> that case, what does it mean if I see a conflict error for an IISet? Can
> they not resolve conflicts internally?

IIRC:  unlike normal adds / removes, bucket splits can cause
un-resolvable conflicts (because more than one persistent object's state
is involved).  In that case, arger buckets should make splits less
frequent, and therefore less likely to conflict.


Tres.
- -- 
===
Tres Seaver  +1 540-429-0999  tsea...@palladion.com
Palladion Software   "Excellence by Design"http://palladion.com
-BEGIN PGP SIGNATURE-
Version: GnuPG v1.4.10 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAk1BnigACgkQ+gerLs4ltQ5nlQCfVxx3V+vtUGWDsyv4iyd/2CRg
v0IAn3sfsBbD2iCJ2lwJzU5i5/IK8e+w
=xMIT
-END PGP SIGNATURE-

___
For more information about ZODB, see the ZODB Wiki:
http://www.zope.org/Wikis/ZODB/

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


Re: [ZODB-Dev] Increasing MAX_BUCKET_SIZE for IISet, etc

2011-01-27 Thread Hanno Schlichting
On Thu, Jan 27, 2011 at 11:09 AM, Matt Hamilton  wrote:
> Hanno Schlichting  hannosch.eu> writes:
>
> There still seem to be instances in which the entire set is loaded.  This
> could be an artifact of the fact I am clearing the ZODB cache before each
> ]test, which I think seems to be clearing the query plan.

Yes. The queryplan is stored in a volatile attribute, so clearing the
zodb cache will throw away the plan. The queryplan version integrated
into Zope 2.13 stores the plan in a module global with thread locks
around it.

> Speaking of
> which I saw in the query plan code, some hook to load a pre-defined query
> plan... but I can't see exactly how you supply this plan or in what format
> it is. Do you use this feature?

You get a plan representation by calling:

http://localhost:8080/Plone/@@catalogqueryplan-prioritymap

Then add an environment variable pointing to a variable inside a module:

[instance]
recipe = plone.recipe.zope2instance
environment-vars =
CATALOGQUERYPLAN my.customer.module.queryplan

Create that module and put the dump in it. it should start with something like:

# query plan dumped at 'Mon May 24 01:33:28 2010'

queryplan = {
  '/Plone/portal_catalog': {
...
}

You can keep updating this plan with some new data from the dump once
in a while.

Ideally this plan should be persisted in the database at certain
intervals, but we haven't implemented that yet. You don't want to
persist the plan in every request doing a catalog query.

Hanno
___
For more information about ZODB, see the ZODB Wiki:
http://www.zope.org/Wikis/ZODB/

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


Re: [ZODB-Dev] Increasing MAX_BUCKET_SIZE for IISet, etc

2011-01-27 Thread Matt Hamilton
Hanno Schlichting  hannosch.eu> writes:

> You are using queryplan in the site, right? The most typical catalog
> query for Plone consists of something like ('allowedRolesAndUsers',
> 'effectiveRange', 'path', 'sort_on'). Without queryplan you indeed
> load the entire tree (or trees inside allowedRolesAndUsers) for each
> of these indexes.

Yes we are using queryplan. Without it the site becomes pretty much 
unusable.
 
> With queryplan it knows from prior execution, that the set returned by
> the path index is the smallest. So it first calculates this. Then it
> uses this small set (usually 10-100 items per folder) to look inside
> the other indexes. It then only needs to do an intersection of the
> small path set with each of the trees. If the path set has less then
> 1000 items, it won't even use the normal intersection function from
> the BTrees module, but use the optimized Cython based version from
> queryplan, which essentially does a for-in loop over the path set.
> Depending on the size ratio between the sets this is up to 20 times
> faster with in-memory data, and even more so if it avoids database
> loads. In the worst case you would load buckets equal to length of the
> path set, usually you should load a lot less.

There still seem to be instances in which the entire set is loaded.  This 
could be an artifact of the fact I am clearing the ZODB cache before each 
]test, which I think seems to be clearing the query plan. Speaking of 
which I saw in the query plan code, some hook to load a pre-defined query 
plan... but I can't see exactly how you supply this plan or in what format 
it is. Do you use this feature?

> We have large Plone sites in the same range of multiple 100.000 items
> and with queryplan and blobs we can run them with ZODB cache sizes of
> less than 100.000 items and memory usage of 500mb per single-threaded
> process.
> 
> Of course it would still be really good to optimize the underlying
> data structures, but queryplan should help make this less urgent.

Well, I think we are already at that point ;) There are also I think other
times in which the full set is loaded.

> > Ahh interesting, that is good to know. I've not actually checked the
> > conflict resolution code, but do bucket change conflicts actually get
> > resolved in some sane way, or does the transaction have to be
> > retried?
> 
> Conflicts inside the same bucket can be resolved and you won't get to
> see any log message for them. If you get a ConflictError in the logs,
> it's one where the request is being retried.

Great. That was that I always thought, but just wanted to check. So in
that case, what does it mean if I see a conflict error for an IISet? Can
they not resolve conflicts internally?

> >> And imagine if you use zc.zlibstorage to compress records! :)
> >
> > This is Plone 3, which is Zope 2.10.11, does zc.zlibstorage work on
> > that, or does it need newer ZODB?
> 
> zc.zlibstorage needs a newer ZODB version. 3.10 and up to be exact.
> 
> > Also, unless I can sort out that
> > large number of small pickles being loaded, I'd imagine this would
> > actually slow things down.
> 
> The Data.fs would be smaller, making it more likely to fit into the OS
> disk cache. The overhead of uncompressing the data is small compared
> to the cost of a disk read instead of a memory read. But it's hard to
> say what exactly happens with the cache ratio in practice.

Yeah, if we could use it I certainly would :) I guess what I mean above is
that larger pickles would compress better, so lots of small pickles the
compression would be less effective.

-Matt




___
For more information about ZODB, see the ZODB Wiki:
http://www.zope.org/Wikis/ZODB/

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


Re: [ZODB-Dev] Increasing MAX_BUCKET_SIZE for IISet, etc

2011-01-27 Thread Hanno Schlichting
Hi.

On Thu, Jan 27, 2011 at 9:00 AM, Matt Hamilton  wrote:
> Alas we are. Or rather, alas, ZCatalog does ;) It would be great if it
> didn't but it's just the way it is. If I have 300,000 items in my
> site, and everyone of them visible to someone with the 'Reader'
> role, then the allowedRolesAndUsers index will have an IITreeSet
> with 300,000 elements in it. Yes, we could try and optimize out that
> specific case, but there are others like that too. If all of my
> items have no effective or expires date, then the same happens with
> the effective range index (DateRangeIndex 'always' set).

You are using queryplan in the site, right? The most typical catalog
query for Plone consists of something like ('allowedRolesAndUsers',
'effectiveRange', 'path', 'sort_on'). Without queryplan you indeed
load the entire tree (or trees inside allowedRolesAndUsers) for each
of these indexes.

With queryplan it knows from prior execution, that the set returned by
the path index is the smallest. So it first calculates this. Then it
uses this small set (usually 10-100 items per folder) to look inside
the other indexes. It then only needs to do an intersection of the
small path set with each of the trees. If the path set has less then
1000 items, it won't even use the normal intersection function from
the BTrees module, but use the optimized Cython based version from
queryplan, which essentially does a for-in loop over the path set.
Depending on the size ratio between the sets this is up to 20 times
faster with in-memory data, and even more so if it avoids database
loads. In the worst case you would load buckets equal to length of the
path set, usually you should load a lot less.

We have large Plone sites in the same range of multiple 100.000 items
and with queryplan and blobs we can run them with ZODB cache sizes of
less than 100.000 items and memory usage of 500mb per single-threaded
process.

Of course it would still be really good to optimize the underlying
data structures, but queryplan should help make this less urgent.

> Ahh interesting, that is good to know. I've not actually checked the
> conflict resolution code, but do bucket change conflicts actually get
> resolved in some sane way, or does the transaction have to be
> retried?

Conflicts inside the same bucket can be resolved and you won't get to
see any log message for them. If you get a ConflictError in the logs,
it's one where the request is being retried.

>> And imagine if you use zc.zlibstorage to compress records! :)
>
> This is Plone 3, which is Zope 2.10.11, does zc.zlibstorage work on
> that, or does it need newer ZODB?

zc.zlibstorage needs a newer ZODB version. 3.10 and up to be exact.

> Also, unless I can sort out that
> large number of small pickles being loaded, I'd imagine this would
> actually slow things down.

The Data.fs would be smaller, making it more likely to fit into the OS
disk cache. The overhead of uncompressing the data is small compared
to the cost of a disk read instead of a memory read. But it's hard to
say what exactly happens with the cache ratio in practice.

Hanno
___
For more information about ZODB, see the ZODB Wiki:
http://www.zope.org/Wikis/ZODB/

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


Re: [ZODB-Dev] Increasing MAX_BUCKET_SIZE for IISet, etc

2011-01-27 Thread Matt Hamilton
Jim Fulton  zope.com> writes:

> 
> On Wed, Jan 26, 2011 at 3:15 PM, Matt Hamilton 
> netsight.co.uk> wrote:

> > So, with up to 300,000 items in some of these IISets, it means to
> > iterate over the entire set (during a Catalog query) means loading
> > 5,000 objects over ZEO from the ZODB, which adds up to quite a bit
> > of
> > latency. With quite a number of these data structures about, means
> > we
> > can end up with in the order of 50,000 object in the ZODB cache
> > *just*
> > for these IISets!
> 
> Hopefully, you're not iterating over the entire tree, but still. :)

Alas we are. Or rather, alas, ZCatalog does ;) It would be great if it
didn't but it's just the way it is. If I have 300,000 items in my 
site, and everyone of them visible to someone with the 'Reader' 
role, then the allowedRolesAndUsers index will have an IITreeSet 
with 300,000 elements in it. Yes, we could try and optimize out that 
specific case, but there are others like that too. If all of my 
items have no effective or expires date, then the same happens with 
the effective range index (DateRangeIndex 'always' set).
 
> > So... has anyone tried increasing the size of MAX_BUCKET_SIZE in
real
> > life?
> 
> We have, mainly to reduce the number of conflicts.
> 
> > I understand that this will increase the potential for conflicts
> > if the bucket/set size is larger (however in reality this probably
> > can't get worse than it is, as currently as the value inserted is
99%
> > of the time greater than the current max value stored -- it is a
> > timestamp -- you always hit the last bucket/set in the tree).
> 
> Actually, it reduces the number of unresolveable conflicts.
> Most conflicting bucket changes can be resolved, but bucket
> splits can't be and bigger buckets means fewer splits.
> 
> The main tradeoff is record size.

Ahh interesting, that is good to know. I've not actually checked the 
conflict resolution code, but do bucket change conflicts actually get
resolved in some sane way, or does the transaction have to be 
retried?

Actually... that is a good point, and something I never thought
of... when you get a Conflict Error in the logs (that was 
resolved) does that mean that _p_resolveConflict was called and 
successful, or does it mean that the transactions were retried 
and that resolved the conflict?

> > I was going to experiment with increasing the MAX_BUCKET_SIZE on
an IISet
> > from 120 to 1200. Doing a quick test, a pickle of an IISet of 60
items
> > is around 336 bytes, an of 600 items is 1580 bytes... so still
very
> > much in the realms of a single disk read / network packet.
> 
> And imagine if you use zc.zlibstorage to compress records! :)

This is Plone 3, which is Zope 2.10.11, does zc.zlibstorage work on
that, or does it need newer ZODB? Also, unless I can sort out that 
large number of small pickles being loaded, I'd imagine this would 
actually slow things down.

> > I'm not sure how the current MAX_BUCKET_SIZE values were
determined,
> > but looks like they have been the same since the dawn of time, and
I'm
> > guessing might be due a tune?
> 
> Probably.
> 
> > It looks like I can change that constant and recompile the BTree
> > package, and it will work fine with existing IISets and just take
> > effect on new sets created (ie clear and rebuild the catalog
index).
> >
> > Anyone played with this before or see any major flaws to my
cunning plan?
> 
> We have.  My long term goal is to arrange things so that you can
> specify/change limits by sub-classing the BTree classes.
> Unfortunately, that's been a long-term priority for too long.
> This could be a great narrow project for someone who's willing
> to grok the Python C APIs.

I remember you introduced me to the C API for things like this wy 
back in Reading at the first non US Zope 3 sprint... I was trying to
create compressed list data structures for catalogs I never could 
quite get rid of the memory leaks I was getting! ;) Maybe I'll be 
brave and take another look.

> Changing the default sizes for the II ad LL BTrees is pretty
  straightforward.
> We were more interested in LO (and similar) BTrees. For those,
> it's much harder to guess sizes because you don't know generally
> how big the objects will be, which is why I'd like to make it
  tunable at the
> application level.

Yeah, I guess that is the issue. I wonder if it would be easy for the
code to work out the total size of the bucket in bytes and then 
split based upon that. Or something like 120 items, or 500kB, 
whichever comes first.

Just looking at the cache on the site at the moment, and we have a
total of 
978,355 objects in cache, of which:

312,523  IOBucket
274,025  IISet
116,136  OOBucket
114,626  IIBucket

So 83% of my cache is just those four object types.

-Matt


___
For more information about ZODB, see the ZODB Wiki:
http://www.zope.org/Wikis/ZODB/

ZODB-Dev mailing list  -  ZODB-Dev@zope.

Re: [ZODB-Dev] Increasing MAX_BUCKET_SIZE for IISet, etc

2011-01-26 Thread Roché Compaan
On Wed, 2011-01-26 at 20:15 +, Matt Hamilton wrote:
> So... has anyone tried increasing the size of MAX_BUCKET_SIZE in real
> life?

I tried back in 2007 but didn't see a big difference. 
https://mail.zope.org/pipermail/zodb-dev/2007-November/011279.html

My benchmark was focussed on writes not on reads though so I think it is
worthwhile to check out.

-- 
Roché Compaan
Upfront Systems   http://www.upfrontsystems.co.za

___
For more information about ZODB, see the ZODB Wiki:
http://www.zope.org/Wikis/ZODB/

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


Re: [ZODB-Dev] Increasing MAX_BUCKET_SIZE for IISet, etc

2011-01-26 Thread Jim Fulton
On Wed, Jan 26, 2011 at 3:15 PM, Matt Hamilton  wrote:
> All,
>  I have been doing some performance investigation into a large Plone
> site we have running. The site in question has approx 300,000 items of
> content. Each piece of content is indexed by ZCatalog.
>
> The main thing I was tracking down was the very large number of
> objects being loaded by the ZODB, mostly IISet instances.
>
> The large numebr of instances seems to be caused by a particular usage
> pattern, in various indexes in the Catalog there are a number of
> IITreeSet instances that are used to map, for instance, time ->
> UID. As content items are added, you end up adding monotonically
> increasing values to a set. The result of this is that you end up
> 'leaving behind' loads of buckets (or IISets in the case of an
> IITreeSet) that are half full.
>
> Looking at the BTrees code, I see there is a MAX_BUCKET_SIZE constant
> that is set for the various BTree/Set types, and in the case of an
> IISet it is set to 120. This means, when inserting into a IITreeSet,
> when the IISet gets beyond 120 items it is split and a new IISet
> created. Hence as above I see a lage number of 60 item IISets due to
> the pattern in which these data structures are filled.
>
> So, with up to 300,000 items in some of these IISets, it means to
> iterate over the entire set (during a Catalog query) means loading
> 5,000 objects over ZEO from the ZODB, which adds up to quite a bit of
> latency. With quite a number of these data structures about, means we
> can end up with in the order of 50,000 object in the ZODB cache *just*
> for these IISets!

Hopefully, you're not iterating over the entire tree, but still. :)

> So... has anyone tried increasing the size of MAX_BUCKET_SIZE in real
> life?

We have, mainly to reduce the number of conflicts.

> I understand that this will increase the potential for conflicts
> if the bucket/set size is larger (however in reality this probably
> can't get worse than it is, as currently as the value inserted is 99%
> of the time greater than the current max value stored -- it is a
> timestamp -- you always hit the last bucket/set in the tree).

Actually, it reduces the number of unresolveable conflicts.
Most conflicting bucket changes can be resolved, but bucket
splits can't be and bigger buckets means fewer splits.

The main tradeoff is record size.

> I was going to experiment with increasing the MAX_BUCKET_SIZE on an IISet
> from 120 to 1200. Doing a quick test, a pickle of an IISet of 60 items
> is around 336 bytes, an of 600 items is 1580 bytes... so still very
> much in the realms of a single disk read / network packet.

And imagine if you use zc.zlibstorage to compress records! :)

> I'm not sure how the current MAX_BUCKET_SIZE values were determined,
> but looks like they have been the same since the dawn of time, and I'm
> guessing might be due a tune?

Probably.

> It looks like I can change that constant and recompile the BTree
> package, and it will work fine with existing IISets and just take
> effect on new sets created (ie clear and rebuild the catalog index).
>
> Anyone played with this before or see any major flaws to my cunning plan?

We have.  My long term goal is to arrange things so that you can
specify/change limits by sub-classing the BTree classes.
Unfortunately, that's been a long-term priority for too long.
This could be a great narrow project for someone who's willing
to grok the Python C APIs.

Changing the default sizes for the II ad LL BTrees is pretty straightforward.
We were more interested in LO (and similar) BTrees. For those,
it's much harder to guess sizes because you don't know generally
how big the objects will be, which is why I'd like to make it tunable at the
application level.

Jim

-- 
Jim Fulton
http://www.linkedin.com/in/jimfulton
___
For more information about ZODB, see the ZODB Wiki:
http://www.zope.org/Wikis/ZODB/

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


Re: [ZODB-Dev] Increasing MAX_BUCKET_SIZE for IISet, etc

2011-01-26 Thread Stefan H. Holek
On 26.01.2011, at 21:15, Matt Hamilton wrote:

> I'm not sure how the current MAX_BUCKET_SIZE values were determined,
> but looks like they have been the same since the dawn of time, and I'm
> guessing might be due a tune?


Go Matt go! :-)

-- 
Stefan H. Holek
ste...@epy.co.at

___
For more information about ZODB, see the ZODB Wiki:
http://www.zope.org/Wikis/ZODB/

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


[ZODB-Dev] Increasing MAX_BUCKET_SIZE for IISet, etc

2011-01-26 Thread Matt Hamilton
All,
  I have been doing some performance investigation into a large Plone
site we have running. The site in question has approx 300,000 items of
content. Each piece of content is indexed by ZCatalog.

The main thing I was tracking down was the very large number of
objects being loaded by the ZODB, mostly IISet instances.

The large numebr of instances seems to be caused by a particular usage
pattern, in various indexes in the Catalog there are a number of
IITreeSet instances that are used to map, for instance, time ->
UID. As content items are added, you end up adding monotonically
increasing values to a set. The result of this is that you end up
'leaving behind' loads of buckets (or IISets in the case of an
IITreeSet) that are half full.

Looking at the BTrees code, I see there is a MAX_BUCKET_SIZE constant
that is set for the various BTree/Set types, and in the case of an
IISet it is set to 120. This means, when inserting into a IITreeSet, 
when the IISet gets beyond 120 items it is split and a new IISet
created. Hence as above I see a lage number of 60 item IISets due to
the pattern in which these data structures are filled.

So, with up to 300,000 items in some of these IISets, it means to
iterate over the entire set (during a Catalog query) means loading
5,000 objects over ZEO from the ZODB, which adds up to quite a bit of
latency. With quite a number of these data structures about, means we
can end up with in the order of 50,000 object in the ZODB cache *just*
for these IISets!

So... has anyone tried increasing the size of MAX_BUCKET_SIZE in real
life? I understand that this will increase the potential for conflicts
if the bucket/set size is larger (however in reality this probably
can't get worse than it is, as currently as the value inserted is 99%
of the time greater than the current max value stored -- it is a
timestamp -- you always hit the last bucket/set in the tree).

I was going to experiment with increasing the MAX_BUCKET_SIZE on an IISet
from 120 to 1200. Doing a quick test, a pickle of an IISet of 60 items
is around 336 bytes, an of 600 items is 1580 bytes... so still very
much in the realms of a single disk read / network packet.

I'm not sure how the current MAX_BUCKET_SIZE values were determined,
but looks like they have been the same since the dawn of time, and I'm
guessing might be due a tune?

It looks like I can change that constant and recompile the BTree
package, and it will work fine with existing IISets and just take
effect on new sets created (ie clear and rebuild the catalog index).

Anyone played with this before or see any major flaws to my cunning plan?

-Matt

___
For more information about ZODB, see the ZODB Wiki:
http://www.zope.org/Wikis/ZODB/

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