From briansheehan78 at gmail.com Wed Aug 1 08:39:18 2007 From: briansheehan78 at gmail.com (Brian Sheehan) Date: Wed, 1 Aug 2007 13:39:18 +0100 Subject: [Betternestedset-talk] Reason why should #parent_id=(x) raise an exception? Message-ID: <92482e8c0708010539i7eac8b18p8b8b042c964671a7@mail.gmail.com> Hi all, Can someone explain to me the reasoning behind the current implementation of the attribute writer for the parent_id column in a nested set object? At the moment it just throws an error: def #{acts_as_nested_set_options[:parent_column]}=(x) raise ActiveRecord::ActiveRecordError, "Unauthorized assignment to #{acts_as_nested_set_options[:parent_column]}: it's an internal field handled by acts_as_nested_set code, use move_to_* methods instead." end Would it not have been possible to define it as something like this: def #{acts_as_nested_set_options[:parent_column]}=(x) move_to_child_of(x) end ? If the above could work, it would allow you to do bulk assignment to the parent_id attribute safely, which would save typing a few lines in controller code... but maybe I'm missing something! thanks, Brian From jc.michel at symetrie.com Wed Aug 1 17:30:16 2007 From: jc.michel at symetrie.com (Jean-Christophe Michel) Date: Wed, 1 Aug 2007 23:30:16 +0200 Subject: [Betternestedset-talk] Reason why should #parent_id=(x) raise an exception? In-Reply-To: <92482e8c0708010539i7eac8b18p8b8b042c964671a7@mail.gmail.com> References: <92482e8c0708010539i7eac8b18p8b8b042c964671a7@mail.gmail.com> Message-ID: <5FC1545F-A73B-4831-94A4-EDF5E83F18DD@symetrie.com> Hi, Le 1 ao?t 07 ? 14:39, Brian Sheehan a ?crit : > Can someone explain to me the reasoning behind the current > implementation of the attribute writer for the parent_id column in a > nested set object? At the moment it just throws an error: > > def #{acts_as_nested_set_options[:parent_column]}=(x) > raise ActiveRecord::ActiveRecordError, "Unauthorized assignment to > #{acts_as_nested_set_options[:parent_column]}: it's an internal > field handled by acts_as_nested_set code, use move_to_* methods > instead." > end > > > Would it not have been possible to define it as something like this: > > def #{acts_as_nested_set_options[:parent_column]}=(x) > move_to_child_of(x) > end There are two reasons: 1. we don't know if it should be the first or the last child of the new parent 2. more importantly, setting a value in AR objects in rails never makes an automatic save of the object instance. Here move_to_child changes not only db values for the current object, but for many others. That's why we think it better not to have a simple method to achieve this change. But feel free to alter this behaviour in your copy if you think it's safe for you ! Jean-Christophe Michel -- symetrie.com Better Nested Set for rails: http://opensource.symetrie.com/trac/better_nested_set From briansheehan78 at gmail.com Wed Aug 1 18:12:03 2007 From: briansheehan78 at gmail.com (Brian Sheehan) Date: Wed, 1 Aug 2007 23:12:03 +0100 Subject: [Betternestedset-talk] Reason why should #parent_id=(x) raise an exception? In-Reply-To: <5FC1545F-A73B-4831-94A4-EDF5E83F18DD@symetrie.com> References: <92482e8c0708010539i7eac8b18p8b8b042c964671a7@mail.gmail.com> <5FC1545F-A73B-4831-94A4-EDF5E83F18DD@symetrie.com> Message-ID: <92482e8c0708011512y241bff2cn4a9d182d57b6e192@mail.gmail.com> Hi Jean-Christophe, That makes sense, thank you! Brian On 8/1/07, Jean-Christophe Michel wrote: > Hi, > > Le 1 ao?t 07 ? 14:39, Brian Sheehan a ?crit : > > Can someone explain to me the reasoning behind the current > > implementation of the attribute writer for the parent_id column in a > > nested set object? At the moment it just throws an error: > > > > def #{acts_as_nested_set_options[:parent_column]}=(x) > > raise ActiveRecord::ActiveRecordError, "Unauthorized assignment to > > #{acts_as_nested_set_options[:parent_column]}: it's an internal > > field handled by acts_as_nested_set code, use move_to_* methods > > instead." > > end > > > > > > Would it not have been possible to define it as something like this: > > > > def #{acts_as_nested_set_options[:parent_column]}=(x) > > move_to_child_of(x) > > end > > There are two reasons: > 1. we don't know if it should be the first or the last child of the > new parent > 2. more importantly, setting a value in AR objects in rails never > makes an automatic save of the object instance. Here move_to_child > changes not only db values for the current object, but for many > others. That's why we think it better not to have a simple method to > achieve this change. > But feel free to alter this behaviour in your copy if you think it's > safe for you ! > > Jean-Christophe Michel > -- > symetrie.com > > Better Nested Set for rails: > http://opensource.symetrie.com/trac/better_nested_set > > > _______________________________________________ > Betternestedset-talk mailing list > Betternestedset-talk at rubyforge.org > http://rubyforge.org/mailman/listinfo/betternestedset-talk > From jonas at fkw.se Mon Aug 6 04:29:07 2007 From: jonas at fkw.se (Jonas Arklint) Date: Mon, 06 Aug 2007 10:29:07 +0200 Subject: [Betternestedset-talk] Display whole tree without requestingdbfor each node In-Reply-To: <000601c7cf82$22dc9cd0$0500000a@rude10> References: <000601c7cf82$22dc9cd0$0500000a@rude10> Message-ID: <46B6DBD3.2090708@fkw.se> I?m a littlebit confused. But how do i accomplish that? Storing level inside db that is. Tekin Suleyman skrev: > Why didn't I think of that! I'll give it a try. > > -----Original Message----- > From: betternestedset-talk-bounces at rubyforge.org > [mailto:betternestedset-talk-bounces at rubyforge.org] On Behalf Of Mikel > Lindsaar > Sent: 25 July 2007 00:20 > To: betternestedset-talk at rubyforge.org > Subject: Re: [Betternestedset-talk] Display whole tree without > requestingdbfor each node > > > If you have this as an ongoing requirement, a "simple" solution might be > storing the level in the model itself in an after save call back. > > It's a bit of a hack, but you can only move the nodes through update > calls anyway... so it might work. Then you have it automagically as an > instance method. > > Regards > > Mikel > > On 7/25/07, Tekin Suleyman wrote: > >> This is something I've wondered also as it more or less cancels out >> any speed gain from getting the full set in one query. Does >> betternestedset provide the hooks to cache the level? Alternatively, >> the parent_id could theoretically be used to calculate levels from a >> full set. >> >> >> >> -----Original Message----- >> From: betternestedset-talk-bounces at rubyforge.org >> [mailto:betternestedset-talk-bounces at rubyforge.org] On Behalf Of >> Jean-Christophe Michel >> Sent: 23 July 2007 22:02 >> To: betternestedset-talk at rubyforge.org >> Subject: Re: [Betternestedset-talk] Display whole tree without >> requesting dbfor each node >> >> >> Hi, >> >> Le 23 juil. 07 ? 17:37, Jonas Arklint a ?crit : >> >>> I?m wondering how I display the whole tree without having to request >>> > > >>> the db each time I use @node.level. >>> >> You have to cache the level in db, or simply compute it in code after >> you read your tree part. >> >> Jean-Christophe Michel >> -- >> symetrie.com >> >> Better Nested Set for rails: >> http://opensource.symetrie.com/trac/better_nested_set >> >> >> _______________________________________________ >> Betternestedset-talk mailing list Betternestedset-talk at rubyforge.org >> http://rubyforge.org/mailman/listinfo/betternestedset-talk >> >> _______________________________________________ >> Betternestedset-talk mailing list Betternestedset-talk at rubyforge.org >> http://rubyforge.org/mailman/listinfo/betternestedset-talk >> >> > _______________________________________________ > Betternestedset-talk mailing list Betternestedset-talk at rubyforge.org > http://rubyforge.org/mailman/listinfo/betternestedset-talk > > _______________________________________________ > Betternestedset-talk mailing list > Betternestedset-talk at rubyforge.org > http://rubyforge.org/mailman/listinfo/betternestedset-talk > > From tekin at raid.nu Mon Aug 6 09:03:42 2007 From: tekin at raid.nu (Tekin Suleyman) Date: Mon, 6 Aug 2007 14:03:42 +0100 Subject: [Betternestedset-talk] Display whole tree without requestingdbfor each node In-Reply-To: <46B6DBD3.2090708@fkw.se> Message-ID: <00d101c7d82a$3734ed30$0500000a@rude10> This isn't actually as straight forward as it might seem. It can't be done in an after_save call back as you end up in an infinite loop. I thought you might be able to do it in a before_save, something like: before_save :cache_level alias_method :old_level, :level def level() self.level_cache; end private def cache_level self.level_cache = self.old_level End And make sure you have a column in your table called level_cache. Now, when you call object.level, it won't make a db call to calculate the level, it will simply return the level_cache attribute. But I'm now not convinced it will exhibit correct behaviour - if old_cache is called before the object is updated, it will cache the current and not the new level, right? Any thoughts? Tekin -----Original Message----- From: betternestedset-talk-bounces at rubyforge.org [mailto:betternestedset-talk-bounces at rubyforge.org] On Behalf Of Jonas Arklint Sent: 06 August 2007 09:29 To: betternestedset-talk at rubyforge.org Subject: Re: [Betternestedset-talk] Display whole tree without requestingdbfor each node I?m a littlebit confused. But how do i accomplish that? Storing level inside db that is. Tekin Suleyman skrev: > Why didn't I think of that! I'll give it a try. > > -----Original Message----- > From: betternestedset-talk-bounces at rubyforge.org > [mailto:betternestedset-talk-bounces at rubyforge.org] On Behalf Of Mikel > Lindsaar > Sent: 25 July 2007 00:20 > To: betternestedset-talk at rubyforge.org > Subject: Re: [Betternestedset-talk] Display whole tree without > requestingdbfor each node > > > If you have this as an ongoing requirement, a "simple" solution might > be storing the level in the model itself in an after save call back. > > It's a bit of a hack, but you can only move the nodes through update > calls anyway... so it might work. Then you have it automagically as > an instance method. > > Regards > > Mikel > > On 7/25/07, Tekin Suleyman wrote: > >> This is something I've wondered also as it more or less cancels out >> any speed gain from getting the full set in one query. Does >> betternestedset provide the hooks to cache the level? Alternatively, >> the parent_id could theoretically be used to calculate levels from a >> full set. >> >> >> >> -----Original Message----- >> From: betternestedset-talk-bounces at rubyforge.org >> [mailto:betternestedset-talk-bounces at rubyforge.org] On Behalf Of >> Jean-Christophe Michel >> Sent: 23 July 2007 22:02 >> To: betternestedset-talk at rubyforge.org >> Subject: Re: [Betternestedset-talk] Display whole tree without >> requesting dbfor each node >> >> >> Hi, >> >> Le 23 juil. 07 ? 17:37, Jonas Arklint a ?crit : >> >>> I?m wondering how I display the whole tree without having to request >>> > > >>> the db each time I use @node.level. >>> >> You have to cache the level in db, or simply compute it in code after >> you read your tree part. >> >> Jean-Christophe Michel >> -- >> symetrie.com >> >> Better Nested Set for rails: >> http://opensource.symetrie.com/trac/better_nested_set >> >> >> _______________________________________________ >> Betternestedset-talk mailing list Betternestedset-talk at rubyforge.org >> http://rubyforge.org/mailman/listinfo/betternestedset-talk >> >> _______________________________________________ >> Betternestedset-talk mailing list Betternestedset-talk at rubyforge.org >> http://rubyforge.org/mailman/listinfo/betternestedset-talk >> >> > _______________________________________________ > Betternestedset-talk mailing list Betternestedset-talk at rubyforge.org > http://rubyforge.org/mailman/listinfo/betternestedset-talk > > _______________________________________________ > Betternestedset-talk mailing list Betternestedset-talk at rubyforge.org > http://rubyforge.org/mailman/listinfo/betternestedset-talk > > _______________________________________________ Betternestedset-talk mailing list Betternestedset-talk at rubyforge.org http://rubyforge.org/mailman/listinfo/betternestedset-talk From briansheehan78 at gmail.com Fri Aug 10 06:58:04 2007 From: briansheehan78 at gmail.com (Brian Sheehan) Date: Fri, 10 Aug 2007 11:58:04 +0100 Subject: [Betternestedset-talk] Display whole tree without requestingdbfor each node In-Reply-To: <00d101c7d82a$3734ed30$0500000a@rude10> References: <46B6DBD3.2090708@fkw.se> <00d101c7d82a$3734ed30$0500000a@rude10> Message-ID: <92482e8c0708100358p305d871cybc3a805bb74a893@mail.gmail.com> I wrote an iterator that iterates through the nested set in a pre-order traversal, yielding each node, it's level, and the relative level of the next node. It can be used to print out ordered lists of the set using only one db access. Here it is: # traverse {|current_node, level, relative_level_of_next| block } # # Iterates through the nodes in the nested set rooted at the receiver, in a pre-order # traversal. For each node visited, it yields that node, its level, and the relative level # of the next node to be visited. The values returned by successive block executions are # accumulated (in an array by default) and returned at the end # # The receiver always has a level of 0. # # If relative_level_of_next is 1, the next node is guaranteed to be the first (i.e. leftmost) child # of the current node # If it is 0, the next node is the next sibling of the the current node # Otherwise, relative level is a negative integer, indicating how many levels above the current node # the next node is def traverse(accum = []) level = 0 pre_order_array = full_set (pre_order_array.size - 1).times do |i| curr_node = pre_order_array[i] next_node = pre_order_array[i + 1] distance = next_node.lft - curr_node.lft relative_level_of_next = -1 * (distance - 2) accum << yield(curr_node, level, relative_level_of_next) level += relative_level_of_next end # Last node is handled differently to the rest: since there is no next node, # the relative_level_of_next is the number of levels back up to the root level relative_level_of_next = - 1 * (pre_order_array.first.rgt - pre_order_array.last.rgt) accum << yield(pre_order_array.last, level, relative_level_of_next) end Hope it helps. Brian On 8/6/07, Tekin Suleyman wrote: > > This isn't actually as straight forward as it might seem. It can't be > done in an after_save call back as you end up in an infinite loop. I > thought you might be able to do it in a before_save, something like: > > before_save :cache_level > alias_method :old_level, :level > def level() self.level_cache; end > > private > def cache_level > self.level_cache = self.old_level > End > > And make sure you have a column in your table called level_cache. Now, > when you call object.level, it won't make a db call to calculate the > level, it will simply return the level_cache attribute. > > But I'm now not convinced it will exhibit correct behaviour - if > old_cache is called before the object is updated, it will cache the > current and not the new level, right? > > Any thoughts? > > Tekin > > > > -----Original Message----- > From: betternestedset-talk-bounces at rubyforge.org > [mailto:betternestedset-talk-bounces at rubyforge.org] On Behalf Of Jonas > Arklint > Sent: 06 August 2007 09:29 > To: betternestedset-talk at rubyforge.org > Subject: Re: [Betternestedset-talk] Display whole tree without > requestingdbfor each node > > > I?m a littlebit confused. But how do i accomplish that? Storing level > inside db that is. > > Tekin Suleyman skrev: > > Why didn't I think of that! I'll give it a try. > > > > -----Original Message----- > > From: betternestedset-talk-bounces at rubyforge.org > > [mailto:betternestedset-talk-bounces at rubyforge.org] On Behalf Of Mikel > > > Lindsaar > > Sent: 25 July 2007 00:20 > > To: betternestedset-talk at rubyforge.org > > Subject: Re: [Betternestedset-talk] Display whole tree without > > requestingdbfor each node > > > > > > If you have this as an ongoing requirement, a "simple" solution might > > be storing the level in the model itself in an after save call back. > > > > It's a bit of a hack, but you can only move the nodes through update > > calls anyway... so it might work. Then you have it automagically as > > an instance method. > > > > Regards > > > > Mikel > > > > On 7/25/07, Tekin Suleyman wrote: > > > >> This is something I've wondered also as it more or less cancels out > >> any speed gain from getting the full set in one query. Does > >> betternestedset provide the hooks to cache the level? Alternatively, > >> the parent_id could theoretically be used to calculate levels from a > >> full set. > >> > >> > >> > >> -----Original Message----- > >> From: betternestedset-talk-bounces at rubyforge.org > >> [mailto:betternestedset-talk-bounces at rubyforge.org] On Behalf Of > >> Jean-Christophe Michel > >> Sent: 23 July 2007 22:02 > >> To: betternestedset-talk at rubyforge.org > >> Subject: Re: [Betternestedset-talk] Display whole tree without > >> requesting dbfor each node > >> > >> > >> Hi, > >> > >> Le 23 juil. 07 ? 17:37, Jonas Arklint a ?crit : > >> > >>> I?m wondering how I display the whole tree without having to request > >>> > > > > > >>> the db each time I use @node.level. > >>> > >> You have to cache the level in db, or simply compute it in code after > >> you read your tree part. > >> > >> Jean-Christophe Michel > >> -- > >> symetrie.com > >> > >> Better Nested Set for rails: > >> http://opensource.symetrie.com/trac/better_nested_set > >> > >> > >> _______________________________________________ > >> Betternestedset-talk mailing list Betternestedset-talk at rubyforge.org > >> http://rubyforge.org/mailman/listinfo/betternestedset-talk > >> > >> _______________________________________________ > >> Betternestedset-talk mailing list Betternestedset-talk at rubyforge.org > >> http://rubyforge.org/mailman/listinfo/betternestedset-talk > >> > >> > > _______________________________________________ > > Betternestedset-talk mailing list Betternestedset-talk at rubyforge.org > > http://rubyforge.org/mailman/listinfo/betternestedset-talk > > > > _______________________________________________ > > Betternestedset-talk mailing list Betternestedset-talk at rubyforge.org > > http://rubyforge.org/mailman/listinfo/betternestedset-talk > > > > > > _______________________________________________ > Betternestedset-talk mailing list Betternestedset-talk at rubyforge.org > http://rubyforge.org/mailman/listinfo/betternestedset-talk > > _______________________________________________ > Betternestedset-talk mailing list > Betternestedset-talk at rubyforge.org > http://rubyforge.org/mailman/listinfo/betternestedset-talk > From tekin at raid.nu Fri Aug 10 07:12:02 2007 From: tekin at raid.nu (Tekin Suleyman) Date: Fri, 10 Aug 2007 12:12:02 +0100 Subject: [Betternestedset-talk] Display whole tree withoutrequestingdbfor each node In-Reply-To: <92482e8c0708100358p305d871cybc3a805bb74a893@mail.gmail.com> Message-ID: <006f01c7db3f$474deba0$0500000a@rude10> Cheers, that looks fantastic! I'll give it a shot and report back. Tekin -----Original Message----- From: betternestedset-talk-bounces at rubyforge.org [mailto:betternestedset-talk-bounces at rubyforge.org] On Behalf Of Brian Sheehan Sent: 10 August 2007 11:58 To: betternestedset-talk at rubyforge.org Subject: Re: [Betternestedset-talk] Display whole tree withoutrequestingdbfor each node I wrote an iterator that iterates through the nested set in a pre-order traversal, yielding each node, it's level, and the relative level of the next node. It can be used to print out ordered lists of the set using only one db access. Here it is: # traverse {|current_node, level, relative_level_of_next| block } # # Iterates through the nodes in the nested set rooted at the receiver, in a pre-order # traversal. For each node visited, it yields that node, its level, and the relative level # of the next node to be visited. The values returned by successive block executions are # accumulated (in an array by default) and returned at the end # # The receiver always has a level of 0. # # If relative_level_of_next is 1, the next node is guaranteed to be the first (i.e. leftmost) child # of the current node # If it is 0, the next node is the next sibling of the the current node # Otherwise, relative level is a negative integer, indicating how many levels above the current node # the next node is def traverse(accum = []) level = 0 pre_order_array = full_set (pre_order_array.size - 1).times do |i| curr_node = pre_order_array[i] next_node = pre_order_array[i + 1] distance = next_node.lft - curr_node.lft relative_level_of_next = -1 * (distance - 2) accum << yield(curr_node, level, relative_level_of_next) level += relative_level_of_next end # Last node is handled differently to the rest: since there is no next node, # the relative_level_of_next is the number of levels back up to the root level relative_level_of_next = - 1 * (pre_order_array.first.rgt - pre_order_array.last.rgt) accum << yield(pre_order_array.last, level, relative_level_of_next) end Hope it helps. Brian On 8/6/07, Tekin Suleyman wrote: > > This isn't actually as straight forward as it might seem. It can't be > done in an after_save call back as you end up in an infinite loop. I > thought you might be able to do it in a before_save, something like: > > before_save :cache_level > alias_method :old_level, :level > def level() self.level_cache; end > > private > def cache_level > self.level_cache = self.old_level > End > > And make sure you have a column in your table called level_cache. Now, > when you call object.level, it won't make a db call to calculate the > level, it will simply return the level_cache attribute. > > But I'm now not convinced it will exhibit correct behaviour - if > old_cache is called before the object is updated, it will cache the > current and not the new level, right? > > Any thoughts? > > Tekin > > > > -----Original Message----- > From: betternestedset-talk-bounces at rubyforge.org > [mailto:betternestedset-talk-bounces at rubyforge.org] On Behalf Of Jonas > Arklint > Sent: 06 August 2007 09:29 > To: betternestedset-talk at rubyforge.org > Subject: Re: [Betternestedset-talk] Display whole tree without > requestingdbfor each node > > > I?m a littlebit confused. But how do i accomplish that? Storing level > inside db that is. > > Tekin Suleyman skrev: > > Why didn't I think of that! I'll give it a try. > > > > -----Original Message----- > > From: betternestedset-talk-bounces at rubyforge.org > > [mailto:betternestedset-talk-bounces at rubyforge.org] On Behalf Of > > Mikel > > > Lindsaar > > Sent: 25 July 2007 00:20 > > To: betternestedset-talk at rubyforge.org > > Subject: Re: [Betternestedset-talk] Display whole tree without > > requestingdbfor each node > > > > > > If you have this as an ongoing requirement, a "simple" solution > > might be storing the level in the model itself in an after save call > > back. > > > > It's a bit of a hack, but you can only move the nodes through update > > calls anyway... so it might work. Then you have it automagically as > > an instance method. > > > > Regards > > > > Mikel > > > > On 7/25/07, Tekin Suleyman wrote: > > > >> This is something I've wondered also as it more or less cancels out > >> any speed gain from getting the full set in one query. Does > >> betternestedset provide the hooks to cache the level? > >> Alternatively, the parent_id could theoretically be used to > >> calculate levels from a full set. > >> > >> > >> > >> -----Original Message----- > >> From: betternestedset-talk-bounces at rubyforge.org > >> [mailto:betternestedset-talk-bounces at rubyforge.org] On Behalf Of > >> Jean-Christophe Michel > >> Sent: 23 July 2007 22:02 > >> To: betternestedset-talk at rubyforge.org > >> Subject: Re: [Betternestedset-talk] Display whole tree without > >> requesting dbfor each node > >> > >> > >> Hi, > >> > >> Le 23 juil. 07 ? 17:37, Jonas Arklint a ?crit : > >> > >>> I?m wondering how I display the whole tree without having to > >>> request > >>> > > > > > >>> the db each time I use @node.level. > >>> > >> You have to cache the level in db, or simply compute it in code > >> after you read your tree part. > >> > >> Jean-Christophe Michel > >> -- > >> symetrie.com > >> > >> Better Nested Set for rails: > >> http://opensource.symetrie.com/trac/better_nested_set > >> > >> > >> _______________________________________________ > >> Betternestedset-talk mailing list > >> Betternestedset-talk at rubyforge.org > >> http://rubyforge.org/mailman/listinfo/betternestedset-talk > >> > >> _______________________________________________ > >> Betternestedset-talk mailing list > >> Betternestedset-talk at rubyforge.org > >> http://rubyforge.org/mailman/listinfo/betternestedset-talk > >> > >> > > _______________________________________________ > > Betternestedset-talk mailing list Betternestedset-talk at rubyforge.org > > http://rubyforge.org/mailman/listinfo/betternestedset-talk > > > > _______________________________________________ > > Betternestedset-talk mailing list Betternestedset-talk at rubyforge.org > > http://rubyforge.org/mailman/listinfo/betternestedset-talk > > > > > > _______________________________________________ > Betternestedset-talk mailing list Betternestedset-talk at rubyforge.org > http://rubyforge.org/mailman/listinfo/betternestedset-talk > > _______________________________________________ > Betternestedset-talk mailing list Betternestedset-talk at rubyforge.org > http://rubyforge.org/mailman/listinfo/betternestedset-talk > _______________________________________________ Betternestedset-talk mailing list Betternestedset-talk at rubyforge.org http://rubyforge.org/mailman/listinfo/betternestedset-talk From tekin at raid.nu Fri Aug 10 09:07:12 2007 From: tekin at raid.nu (Tekin Suleyman) Date: Fri, 10 Aug 2007 14:07:12 +0100 Subject: [Betternestedset-talk] Display whole tree withoutrequestingdbfor each node In-Reply-To: <92482e8c0708100358p305d871cybc3a805bb74a893@mail.gmail.com> Message-ID: <00a701c7db4f$5f7c00d0$0500000a@rude10> Works a treat! I modified it slightly as I have several roots and want the whole thing traversed: I made it a class method and instead of full_set it calls complete_set. Thanks Brian, very handy indeed. Tekin -----Original Message----- From: betternestedset-talk-bounces at rubyforge.org [mailto:betternestedset-talk-bounces at rubyforge.org] On Behalf Of Brian Sheehan Sent: 10 August 2007 11:58 To: betternestedset-talk at rubyforge.org Subject: Re: [Betternestedset-talk] Display whole tree withoutrequestingdbfor each node I wrote an iterator that iterates through the nested set in a pre-order traversal, yielding each node, it's level, and the relative level of the next node. It can be used to print out ordered lists of the set using only one db access. Here it is: # traverse {|current_node, level, relative_level_of_next| block } # # Iterates through the nodes in the nested set rooted at the receiver, in a pre-order # traversal. For each node visited, it yields that node, its level, and the relative level # of the next node to be visited. The values returned by successive block executions are # accumulated (in an array by default) and returned at the end # # The receiver always has a level of 0. # # If relative_level_of_next is 1, the next node is guaranteed to be the first (i.e. leftmost) child # of the current node # If it is 0, the next node is the next sibling of the the current node # Otherwise, relative level is a negative integer, indicating how many levels above the current node # the next node is def traverse(accum = []) level = 0 pre_order_array = full_set (pre_order_array.size - 1).times do |i| curr_node = pre_order_array[i] next_node = pre_order_array[i + 1] distance = next_node.lft - curr_node.lft relative_level_of_next = -1 * (distance - 2) accum << yield(curr_node, level, relative_level_of_next) level += relative_level_of_next end # Last node is handled differently to the rest: since there is no next node, # the relative_level_of_next is the number of levels back up to the root level relative_level_of_next = - 1 * (pre_order_array.first.rgt - pre_order_array.last.rgt) accum << yield(pre_order_array.last, level, relative_level_of_next) end Hope it helps. Brian On 8/6/07, Tekin Suleyman wrote: > > This isn't actually as straight forward as it might seem. It can't be > done in an after_save call back as you end up in an infinite loop. I > thought you might be able to do it in a before_save, something like: > > before_save :cache_level > alias_method :old_level, :level > def level() self.level_cache; end > > private > def cache_level > self.level_cache = self.old_level > End > > And make sure you have a column in your table called level_cache. Now, > when you call object.level, it won't make a db call to calculate the > level, it will simply return the level_cache attribute. > > But I'm now not convinced it will exhibit correct behaviour - if > old_cache is called before the object is updated, it will cache the > current and not the new level, right? > > Any thoughts? > > Tekin > > > > -----Original Message----- > From: betternestedset-talk-bounces at rubyforge.org > [mailto:betternestedset-talk-bounces at rubyforge.org] On Behalf Of Jonas > Arklint > Sent: 06 August 2007 09:29 > To: betternestedset-talk at rubyforge.org > Subject: Re: [Betternestedset-talk] Display whole tree without > requestingdbfor each node > > > I?m a littlebit confused. But how do i accomplish that? Storing level > inside db that is. > > Tekin Suleyman skrev: > > Why didn't I think of that! I'll give it a try. > > > > -----Original Message----- > > From: betternestedset-talk-bounces at rubyforge.org > > [mailto:betternestedset-talk-bounces at rubyforge.org] On Behalf Of > > Mikel > > > Lindsaar > > Sent: 25 July 2007 00:20 > > To: betternestedset-talk at rubyforge.org > > Subject: Re: [Betternestedset-talk] Display whole tree without > > requestingdbfor each node > > > > > > If you have this as an ongoing requirement, a "simple" solution > > might be storing the level in the model itself in an after save call > > back. > > > > It's a bit of a hack, but you can only move the nodes through update > > calls anyway... so it might work. Then you have it automagically as > > an instance method. > > > > Regards > > > > Mikel > > > > On 7/25/07, Tekin Suleyman wrote: > > > >> This is something I've wondered also as it more or less cancels out > >> any speed gain from getting the full set in one query. Does > >> betternestedset provide the hooks to cache the level? > >> Alternatively, the parent_id could theoretically be used to > >> calculate levels from a full set. > >> > >> > >> > >> -----Original Message----- > >> From: betternestedset-talk-bounces at rubyforge.org > >> [mailto:betternestedset-talk-bounces at rubyforge.org] On Behalf Of > >> Jean-Christophe Michel > >> Sent: 23 July 2007 22:02 > >> To: betternestedset-talk at rubyforge.org > >> Subject: Re: [Betternestedset-talk] Display whole tree without > >> requesting dbfor each node > >> > >> > >> Hi, > >> > >> Le 23 juil. 07 ? 17:37, Jonas Arklint a ?crit : > >> > >>> I?m wondering how I display the whole tree without having to > >>> request > >>> > > > > > >>> the db each time I use @node.level. > >>> > >> You have to cache the level in db, or simply compute it in code > >> after you read your tree part. > >> > >> Jean-Christophe Michel > >> -- > >> symetrie.com > >> > >> Better Nested Set for rails: > >> http://opensource.symetrie.com/trac/better_nested_set > >> > >> > >> _______________________________________________ > >> Betternestedset-talk mailing list > >> Betternestedset-talk at rubyforge.org > >> http://rubyforge.org/mailman/listinfo/betternestedset-talk > >> > >> _______________________________________________ > >> Betternestedset-talk mailing list > >> Betternestedset-talk at rubyforge.org > >> http://rubyforge.org/mailman/listinfo/betternestedset-talk > >> > >> > > _______________________________________________ > > Betternestedset-talk mailing list Betternestedset-talk at rubyforge.org > > http://rubyforge.org/mailman/listinfo/betternestedset-talk > > > > _______________________________________________ > > Betternestedset-talk mailing list Betternestedset-talk at rubyforge.org > > http://rubyforge.org/mailman/listinfo/betternestedset-talk > > > > > > _______________________________________________ > Betternestedset-talk mailing list Betternestedset-talk at rubyforge.org > http://rubyforge.org/mailman/listinfo/betternestedset-talk > > _______________________________________________ > Betternestedset-talk mailing list Betternestedset-talk at rubyforge.org > http://rubyforge.org/mailman/listinfo/betternestedset-talk > _______________________________________________ Betternestedset-talk mailing list Betternestedset-talk at rubyforge.org http://rubyforge.org/mailman/listinfo/betternestedset-talk -------------- next part -------------- A non-text attachment was scrubbed... Name: add_traverse_function.patch Type: application/octet-stream Size: 22991 bytes Desc: not available Url : http://rubyforge.org/pipermail/betternestedset-talk/attachments/20070810/e3db03f2/attachment-0001.obj From briansheehan78 at gmail.com Fri Aug 10 11:23:50 2007 From: briansheehan78 at gmail.com (Brian Sheehan) Date: Fri, 10 Aug 2007 16:23:50 +0100 Subject: [Betternestedset-talk] Display whole tree withoutrequestingdbfor each node In-Reply-To: <00a701c7db4f$5f7c00d0$0500000a@rude10> References: <92482e8c0708100358p305d871cybc3a805bb74a893@mail.gmail.com> <00a701c7db4f$5f7c00d0$0500000a@rude10> Message-ID: <92482e8c0708100823l176fa977hd1b5ae00233a7259@mail.gmail.com> Glad to hear it. I haven't done much testing on that method, so post back if you run into any issues. thanks for the patch, Brian On 8/10/07, Tekin Suleyman wrote: > Works a treat! > > I modified it slightly as I have several roots and want the whole thing > traversed: I made it a class method and instead of full_set it calls > complete_set. > Thanks Brian, very handy indeed. > > Tekin > > -----Original Message----- > From: betternestedset-talk-bounces at rubyforge.org > [mailto:betternestedset-talk-bounces at rubyforge.org] On Behalf Of Brian > Sheehan > Sent: 10 August 2007 11:58 > To: betternestedset-talk at rubyforge.org > Subject: Re: [Betternestedset-talk] Display whole tree > withoutrequestingdbfor each node > > > I wrote an iterator that iterates through the nested set in a pre-order > traversal, yielding each node, it's level, and the relative level of the > next node. It can be used to print out ordered lists of the set using > only one db access. Here it is: > > # traverse {|current_node, level, relative_level_of_next| block } > # > # Iterates through the nodes in the nested set rooted at the receiver, > in a pre-order > # traversal. For each node visited, it yields that node, its level, > and the relative level > # of the next node to be visited. The values returned by successive > block executions are > # accumulated (in an array by default) and returned at the end > # > # The receiver always has a level of 0. > # > # If relative_level_of_next is 1, the next node is guaranteed to be > the first (i.e. leftmost) child > # of the current node > # If it is 0, the next node is the next sibling of the the current > node > # Otherwise, relative level is a negative integer, indicating how many > levels above the current node > # the next node is > def traverse(accum = []) > level = 0 > pre_order_array = full_set > (pre_order_array.size - 1).times do |i| > curr_node = pre_order_array[i] > next_node = pre_order_array[i + 1] > distance = next_node.lft - curr_node.lft > relative_level_of_next = -1 * (distance - 2) > accum << yield(curr_node, level, relative_level_of_next) > level += relative_level_of_next > end > # Last node is handled differently to the rest: since there is no > next node, > # the relative_level_of_next is the number of levels back up to the > root level > relative_level_of_next = - 1 * (pre_order_array.first.rgt - > pre_order_array.last.rgt) > accum << yield(pre_order_array.last, level, relative_level_of_next) > end > > Hope it helps. > > Brian > > On 8/6/07, Tekin Suleyman wrote: > > > > This isn't actually as straight forward as it might seem. It can't be > > done in an after_save call back as you end up in an infinite loop. I > > thought you might be able to do it in a before_save, something like: > > > > before_save :cache_level > > alias_method :old_level, :level > > def level() self.level_cache; end > > > > private > > def cache_level > > self.level_cache = self.old_level > > End > > > > And make sure you have a column in your table called level_cache. Now, > > > when you call object.level, it won't make a db call to calculate the > > level, it will simply return the level_cache attribute. > > > > But I'm now not convinced it will exhibit correct behaviour - if > > old_cache is called before the object is updated, it will cache the > > current and not the new level, right? > > > > Any thoughts? > > > > Tekin > > > > > > > > -----Original Message----- > > From: betternestedset-talk-bounces at rubyforge.org > > [mailto:betternestedset-talk-bounces at rubyforge.org] On Behalf Of Jonas > > > Arklint > > Sent: 06 August 2007 09:29 > > To: betternestedset-talk at rubyforge.org > > Subject: Re: [Betternestedset-talk] Display whole tree without > > requestingdbfor each node > > > > > > I?m a littlebit confused. But how do i accomplish that? Storing level > > inside db that is. > > > > Tekin Suleyman skrev: > > > Why didn't I think of that! I'll give it a try. > > > > > > -----Original Message----- > > > From: betternestedset-talk-bounces at rubyforge.org > > > [mailto:betternestedset-talk-bounces at rubyforge.org] On Behalf Of > > > Mikel > > > > > Lindsaar > > > Sent: 25 July 2007 00:20 > > > To: betternestedset-talk at rubyforge.org > > > Subject: Re: [Betternestedset-talk] Display whole tree without > > > requestingdbfor each node > > > > > > > > > If you have this as an ongoing requirement, a "simple" solution > > > might be storing the level in the model itself in an after save call > > > > back. > > > > > > It's a bit of a hack, but you can only move the nodes through update > > > > calls anyway... so it might work. Then you have it automagically as > > > > an instance method. > > > > > > Regards > > > > > > Mikel > > > > > > On 7/25/07, Tekin Suleyman wrote: > > > > > >> This is something I've wondered also as it more or less cancels out > > > >> any speed gain from getting the full set in one query. Does > > >> betternestedset provide the hooks to cache the level? > > >> Alternatively, the parent_id could theoretically be used to > > >> calculate levels from a full set. > > >> > > >> > > >> > > >> -----Original Message----- > > >> From: betternestedset-talk-bounces at rubyforge.org > > >> [mailto:betternestedset-talk-bounces at rubyforge.org] On Behalf Of > > >> Jean-Christophe Michel > > >> Sent: 23 July 2007 22:02 > > >> To: betternestedset-talk at rubyforge.org > > >> Subject: Re: [Betternestedset-talk] Display whole tree without > > >> requesting dbfor each node > > >> > > >> > > >> Hi, > > >> > > >> Le 23 juil. 07 ? 17:37, Jonas Arklint a ?crit : > > >> > > >>> I?m wondering how I display the whole tree without having to > > >>> request > > >>> > > > > > > > > >>> the db each time I use @node.level. > > >>> > > >> You have to cache the level in db, or simply compute it in code > > >> after you read your tree part. > > >> > > >> Jean-Christophe Michel > > >> -- > > >> symetrie.com > > >> > > >> Better Nested Set for rails: > > >> http://opensource.symetrie.com/trac/better_nested_set > > >> > > >> > > >> _______________________________________________ > > >> Betternestedset-talk mailing list > > >> Betternestedset-talk at rubyforge.org > > >> http://rubyforge.org/mailman/listinfo/betternestedset-talk > > >> > > >> _______________________________________________ > > >> Betternestedset-talk mailing list > > >> Betternestedset-talk at rubyforge.org > > >> http://rubyforge.org/mailman/listinfo/betternestedset-talk > > >> > > >> > > > _______________________________________________ > > > Betternestedset-talk mailing list Betternestedset-talk at rubyforge.org > > > http://rubyforge.org/mailman/listinfo/betternestedset-talk > > > > > > _______________________________________________ > > > Betternestedset-talk mailing list Betternestedset-talk at rubyforge.org > > > http://rubyforge.org/mailman/listinfo/betternestedset-talk > > > > > > > > > > _______________________________________________ > > Betternestedset-talk mailing list Betternestedset-talk at rubyforge.org > > http://rubyforge.org/mailman/listinfo/betternestedset-talk > > > > _______________________________________________ > > Betternestedset-talk mailing list Betternestedset-talk at rubyforge.org > > http://rubyforge.org/mailman/listinfo/betternestedset-talk > > > _______________________________________________ > Betternestedset-talk mailing list Betternestedset-talk at rubyforge.org > http://rubyforge.org/mailman/listinfo/betternestedset-talk > > _______________________________________________ > Betternestedset-talk mailing list > Betternestedset-talk at rubyforge.org > http://rubyforge.org/mailman/listinfo/betternestedset-talk > > > From rogishmn at muohio.edu Tue Aug 14 13:15:17 2007 From: rogishmn at muohio.edu (Matt Rogish) Date: Tue, 14 Aug 2007 13:15:17 -0400 Subject: [Betternestedset-talk] Concurrency issues? Message-ID: Under heavy load we are getting significantly screwed up data. I have to run renumber_full_tree in script/console production order to repair the thing. Obviously this is a bad thing, but I don't even know where to start to fix it. Any ideas? Thanks, -- Matt -------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/betternestedset-talk/attachments/20070814/b5ecbe36/attachment.html From rogishmn at muohio.edu Tue Aug 14 13:41:39 2007 From: rogishmn at muohio.edu (Matt Rogish) Date: Tue, 14 Aug 2007 13:41:39 -0400 Subject: [Betternestedset-talk] Concurrency issues? In-Reply-To: References: Message-ID: How can I repair my tree? I have a message board system in which the messages are grouped by "message_board_id", thus my model is: acts_as_nested_set :scope => :message_board_id Somehow the tree is messed up, inasmuch as some roots (parent_id == null) are being set to the children of some other message, so I cannot successfully repair it. I'm not sure if I'm performing incorrect operations or what, but somehow I need to repair my tree where message_board_id = 34 (or whatever it is). It seems as if renumber_full_tree tries to find the virtual root for a given node, but since the root itself is a CHILD of another node, the whole thing fails. My layman's guess is that the "root" condition is wrong, since it's doing WHERE parent_id IS NULL ... AND lft BETWEEN .. AND .. Well, if the root is incorrectly between something, then the lft would fail, no? Maybe I'm misreading that. Help!! Thanks, -- Matt On 8/14/07, Matt Rogish wrote: > > Under heavy load we are getting significantly screwed up data. I have to > run renumber_full_tree in script/console production order to repair the > thing. > > Obviously this is a bad thing, but I don't even know where to start to fix > it. Any ideas? > > Thanks, > > -- > Matt > -------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/betternestedset-talk/attachments/20070814/b9203792/attachment.html From jnicoll at goldnoteexpress.com Tue Aug 14 13:45:50 2007 From: jnicoll at goldnoteexpress.com (Jeremy Nicoll) Date: Tue, 14 Aug 2007 11:45:50 -0600 Subject: [Betternestedset-talk] Concurrency issues? In-Reply-To: References: Message-ID: <46C1EA4E.7000707@goldnoteexpress.com> I think it would be best if you could post your SQL that is messed up as well as the code you are using to save your nodes. Unfortunately we can't tell you what is wrong until we actually see the logic behind what you are doing. -- Jeremy Nicoll Matt Rogish wrote: > How can I repair my tree? > > I have a message board system in which the messages are grouped by > "message_board_id", thus my model is: > acts_as_nested_set :scope => :message_board_id > > Somehow the tree is messed up, inasmuch as some roots (parent_id == > null) are being set to the children of some other message, so I cannot > successfully repair it. I'm not sure if I'm performing incorrect > operations or what, but somehow I need to repair my tree where > message_board_id = 34 (or whatever it is). > > It seems as if renumber_full_tree tries to find the virtual root for a > given node, but since the root itself is a CHILD of another node, the > whole thing fails. My layman's guess is that the "root" condition is > wrong, since it's doing WHERE parent_id IS NULL ... AND lft BETWEEN .. > AND .. > > Well, if the root is incorrectly between something, then the lft would > fail, no? Maybe I'm misreading that. Help!! > > Thanks, > > -- > Matt > > On 8/14/07, * Matt Rogish* > wrote: > > Under heavy load we are getting significantly screwed up data. I > have to run renumber_full_tree in script/console production order > to repair the thing. > > Obviously this is a bad thing, but I don't even know where to > start to fix it. Any ideas? > > Thanks, > > -- > Matt > > > ------------------------------------------------------------------------ > > _______________________________________________ > Betternestedset-talk mailing list > Betternestedset-talk at rubyforge.org > http://rubyforge.org/mailman/listinfo/betternestedset-talk > -------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/betternestedset-talk/attachments/20070814/e3e6bb18/attachment.html From rogishmn at muohio.edu Tue Aug 14 14:08:24 2007 From: rogishmn at muohio.edu (Matt Rogish) Date: Tue, 14 Aug 2007 14:08:24 -0400 Subject: [Betternestedset-talk] Concurrency issues? In-Reply-To: <46C1EA4E.7000707@goldnoteexpress.com> References: <46C1EA4E.7000707@goldnoteexpress.com> Message-ID: I'm not writing any SQL, I'm using built-in better-nested-set functions. Here's my save: def create @message = Message.new(params[:message]) if @message.save flash[:notice] = 'Message was successfully created.' if params[:message][:parent_id] @message.move_to_child_of( Message.find params[:message][:parent_id] ) @message.save end end end -- Matt On 8/14/07, Jeremy Nicoll wrote: > > I think it would be best if you could post your SQL that is messed up > as well as the code you are using to save your nodes. Unfortunately we > can't tell you what is wrong until we actually see the logic behind what you > are doing. > > -- > Jeremy Nicoll > > Matt Rogish wrote: > > How can I repair my tree? > > I have a message board system in which the messages are grouped by > "message_board_id", thus my model is: > acts_as_nested_set :scope => :message_board_id > > Somehow the tree is messed up, inasmuch as some roots (parent_id == null) > are being set to the children of some other message, so I cannot > successfully repair it. I'm not sure if I'm performing incorrect operations > or what, but somehow I need to repair my tree where message_board_id = 34 > (or whatever it is). > > It seems as if renumber_full_tree tries to find the virtual root for a > given node, but since the root itself is a CHILD of another node, the whole > thing fails. My layman's guess is that the "root" condition is wrong, since > it's doing WHERE parent_id IS NULL ... AND lft BETWEEN .. AND .. > > Well, if the root is incorrectly between something, then the lft would > fail, no? Maybe I'm misreading that. Help!! > > Thanks, > > -- > Matt > > On 8/14/07, Matt Rogish wrote: > > > > Under heavy load we are getting significantly screwed up data. I have to > > run renumber_full_tree in script/console production order to repair the > > thing. > > > > Obviously this is a bad thing, but I don't even know where to start to > > fix it. Any ideas? > > > > Thanks, > > > > -- > > Matt > > > > ------------------------------ > > _______________________________________________ > Betternestedset-talk mailing list > Betternestedset-talk at rubyforge.org > http://rubyforge.org/mailman/listinfo/betternestedset-talk > > > _______________________________________________ > Betternestedset-talk mailing list > Betternestedset-talk at rubyforge.org > http://rubyforge.org/mailman/listinfo/betternestedset-talk > > -------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/betternestedset-talk/attachments/20070814/73cde471/attachment-0001.html From dontfall at gmail.com Tue Aug 14 14:21:52 2007 From: dontfall at gmail.com (Krishna Dole) Date: Tue, 14 Aug 2007 14:21:52 -0400 Subject: [Betternestedset-talk] Concurrency issues? In-Reply-To: References: <46C1EA4E.7000707@goldnoteexpress.com> Message-ID: <8d64b97d0708141121i4430f4e5jea5aeab2bb7176df@mail.gmail.com> Hi Matt, Is this the only code you have that alters the tree? Any delete/move code? Also, are you using a transactional storage engine? (basically anything other than MyISAM, I think). I presume the message_board_id is being set from params[:message]. Krishna On 8/14/07, Matt Rogish wrote: > I'm not writing any SQL, I'm using built-in better-nested-set functions. > > Here's my save: > def create > @message = Message.new(params[:message]) > > if @message.save > flash[:notice] = 'Message was successfully created.' > > if params[:message][:parent_id] > @message.move_to_child_of( Message.find params[:message][:parent_id] > ) > @message.save > end > end > end > > -- > Matt > > > > On 8/14/07, Jeremy Nicoll wrote: > > > > I think it would be best if you could post your SQL that is messed up > as well as the code you are using to save your nodes. Unfortunately we > can't tell you what is wrong until we actually see the logic behind what you > are doing. > > > > -- > > Jeremy Nicoll > > > > Matt Rogish wrote: > > > > How can I repair my tree? > > > > I have a message board system in which the messages are grouped by > "message_board_id", thus my model is: > > acts_as_nested_set :scope => :message_board_id > > > > Somehow the tree is messed up, inasmuch as some roots (parent_id == null) > are being set to the children of some other message, so I cannot > successfully repair it. I'm not sure if I'm performing incorrect operations > or what, but somehow I need to repair my tree where message_board_id = 34 > (or whatever it is). > > > > It seems as if renumber_full_tree tries to find the virtual root for a > given node, but since the root itself is a CHILD of another node, the whole > thing fails. My layman's guess is that the "root" condition is wrong, since > it's doing WHERE parent_id IS NULL ... AND lft BETWEEN .. AND .. > > > > Well, if the root is incorrectly between something, then the lft would > fail, no? Maybe I'm misreading that. Help!! > > > > Thanks, > > > > -- > > Matt > > > > > > On 8/14/07, Matt Rogish wrote: > > > Under heavy load we are getting significantly screwed up data. I have to > run renumber_full_tree in script/console production order to repair the > thing. > > > > > > Obviously this is a bad thing, but I don't even know where to start to > fix it. Any ideas? > > > > > > Thanks, > > > > > > -- > > > Matt > > > > > > > ________________________________ > > > _______________________________________________ > > Betternestedset-talk mailing list > > Betternestedset-talk at rubyforge.org > > > > > > > http://rubyforge.org/mailman/listinfo/betternestedset-talk > > > > > > _______________________________________________ > > Betternestedset-talk mailing list > > Betternestedset-talk at rubyforge.org > > > http://rubyforge.org/mailman/listinfo/betternestedset-talk > > > > > > > _______________________________________________ > Betternestedset-talk mailing list > Betternestedset-talk at rubyforge.org > http://rubyforge.org/mailman/listinfo/betternestedset-talk > > From rogishmn at muohio.edu Tue Aug 14 14:46:02 2007 From: rogishmn at muohio.edu (Matt Rogish) Date: Tue, 14 Aug 2007 14:46:02 -0400 Subject: [Betternestedset-talk] Fwd: Concurrency issues? In-Reply-To: References: <46C1EA4E.7000707@goldnoteexpress.com> Message-ID: The problem is, as I see it, overlapping left and right columns. Shouldn't the lft/right be one apart, or am I wrong. For example: mysql> select id, parent_id, lft, rgt from messages where message_board_id = 1926 and parent_id is null order by lft; +--------+-----------+------+------+ | id | parent_id | lft | rgt | +--------+-----------+------+------+ | 9472 | NULL | 1 | 2 | | 9473 | NULL | 2 | 37 | | 9474 | NULL | 37 | 44 | | 9475 | NULL | 44 | 45 | | 9476 | NULL | 45 | 74 | | 9477 | NULL | 74 | 75 | | 9478 | NULL | 75 | 114 | | 9487 | NULL | 114 | 179 | | 9479 | NULL | 179 | 348 | | 9488 | NULL | 478 | 515 | | 9482 | NULL | 515 | 520 | | 9483 | NULL | 520 | 525 | | 9484 | NULL | 525 | 526 | | 9485 | NULL | 526 | 579 | | 334881 | NULL | 579 | 580 | | 335201 | NULL | 581 | 584 | | 335234 | NULL | 585 | 586 | +--------+-----------+------+------+ So the only ones "correct" are id = 335201 and id = 335234? I attached the entire dataset. What is happening is that the BETWEEN statement that better nested set is executing looks something like this: m = Message.find( 9478 ) m.all_children.each{ stuff } SQL is: SELECT * FROM messages WHERE (message_board_id = 1926 AND (lft BETWEEN 75 AND 114)) ORDER BY lf Since BETWEEN is inclusive, that result pulls all the children correctly but incorrectly pulls out the next root, message id = 9487. I'm not sure if that means renumber_entire_tree needs to be fixed, or the actual move_to_child does, but something isn't right. -- Matt On 8/14/07, Matt Rogish wrote: > > I'm not writing any SQL, I'm using built-in better-nested-set functions. > > Here's my save: > def create > @message = Message.new(params[:message]) > > if @message.save > flash[:notice] = 'Message was successfully created.' > > if params[:message][:parent_id] > @message.move_to_child_of( Message.findparams[:message][:parent_id] ) > @message.save > end > end > end > > -- > Matt > > On 8/14/07, Jeremy Nicoll wrote: > > > > I think it would be best if you could post your SQL that is messed > > up as well as the code you are using to save your nodes. Unfortunately we > > can't tell you what is wrong until we actually see the logic behind what you > > are doing. > > > > -- > > Jeremy Nicoll > > > > Matt Rogish wrote: > > > > How can I repair my tree? > > > > I have a message board system in which the messages are grouped by > > "message_board_id", thus my model is: > > acts_as_nested_set :scope => :message_board_id > > > > Somehow the tree is messed up, inasmuch as some roots (parent_id == > > null) are being set to the children of some other message, so I cannot > > successfully repair it. I'm not sure if I'm performing incorrect operations > > or what, but somehow I need to repair my tree where message_board_id = 34 > > (or whatever it is). > > > > It seems as if renumber_full_tree tries to find the virtual root for a > > given node, but since the root itself is a CHILD of another node, the whole > > thing fails. My layman's guess is that the "root" condition is wrong, since > > it's doing WHERE parent_id IS NULL ... AND lft BETWEEN .. AND .. > > > > Well, if the root is incorrectly between something, then the lft would > > fail, no? Maybe I'm misreading that. Help!! > > > > Thanks, > > > > -- > > Matt > > > > On 8/14/07, Matt Rogish wrote: > > > > > > Under heavy load we are getting significantly screwed up data. I have > > > to run renumber_full_tree in script/console production order to repair the > > > thing. > > > > > > Obviously this is a bad thing, but I don't even know where to start to > > > fix it. Any ideas? > > > > > > Thanks, > > > > > > -- > > > Matt > > > > > > > ------------------------------ > > > > _______________________________________________ > > Betternestedset-talk mailing list > > Betternestedset-talk at rubyforge.org > > > > > > http://rubyforge.org/mailman/listinfo/betternestedset-talk > > > > > > _______________________________________________ > > Betternestedset-talk mailing list > > Betternestedset-talk at rubyforge.org > > http://rubyforge.org/mailman/listinfo/betternestedset-talk > > > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/betternestedset-talk/attachments/20070814/3541a709/attachment-0001.html -------------- next part -------------- mysql> select id, parent_id, lft, rgt from messages where message_board_id = 1926 order by lft; +--------+-----------+------+------+ | id | parent_id | lft | rgt | +--------+-----------+------+------+ | 9472 | NULL | 1 | 2 | | 9473 | NULL | 2 | 37 | | 333572 | 9473 | 3 | 6 | | 334896 | 333572 | 4 | 5 | | 334709 | 9473 | 7 | 8 | | 334858 | 9473 | 9 | 12 | | 335248 | 334858 | 10 | 11 | | 334859 | 9473 | 13 | 14 | | 334860 | 9473 | 15 | 16 | | 334861 | 9473 | 17 | 18 | | 334862 | 9473 | 19 | 24 | | 335243 | 334862 | 20 | 21 | | 335255 | 334862 | 22 | 23 | | 335242 | 9473 | 25 | 26 | | 335247 | 9473 | 27 | 28 | | 335251 | 9473 | 29 | 32 | | 335254 | 335251 | 30 | 31 | | 335256 | 9473 | 33 | 34 | | 335297 | 9473 | 35 | 36 | | 9474 | NULL | 37 | 44 | | 334934 | 9474 | 38 | 39 | | 334994 | 9474 | 40 | 41 | | 335215 | 9474 | 42 | 43 | | 9475 | NULL | 44 | 45 | | 9476 | NULL | 45 | 74 | | 334903 | 9476 | 46 | 47 | | 334904 | 9476 | 48 | 49 | | 334905 | 9476 | 50 | 51 | | 334906 | 9476 | 52 | 53 | | 334907 | 9476 | 54 | 55 | | 334908 | 9476 | 56 | 57 | | 334909 | 9476 | 58 | 59 | | 334910 | 9476 | 60 | 61 | | 334911 | 9476 | 62 | 63 | | 334913 | 9476 | 64 | 65 | | 335222 | 9476 | 66 | 67 | | 335223 | 9476 | 68 | 69 | | 335224 | 9476 | 70 | 71 | | 335225 | 9476 | 72 | 73 | | 9477 | NULL | 74 | 75 | | 9478 | NULL | 75 | 114 | | 334804 | 9478 | 76 | 77 | | 334805 | 9478 | 78 | 79 | | 334806 | 9478 | 80 | 81 | | 334826 | 9478 | 82 | 83 | | 334847 | 9478 | 84 | 85 | | 334849 | 9478 | 86 | 87 | | 334917 | 9478 | 88 | 89 | | 334936 | 9478 | 90 | 91 | | 334955 | 9478 | 92 | 93 | | 334974 | 9478 | 94 | 95 | | 334984 | 9478 | 96 | 97 | | 335185 | 9478 | 98 | 99 | | 335186 | 9478 | 100 | 101 | | 335187 | 9478 | 102 | 103 | | 335188 | 9478 | 104 | 105 | | 335189 | 9478 | 106 | 107 | | 335190 | 9478 | 108 | 109 | | 335191 | 9478 | 110 | 111 | | 335241 | 9478 | 112 | 113 | | 9487 | NULL | 114 | 179 | | 334916 | 9487 | 115 | 116 | | 334800 | 9487 | 117 | 118 | | 334801 | 9487 | 119 | 120 | | 334802 | 9487 | 121 | 122 | | 334752 | 9487 | 123 | 124 | | 334729 | 9487 | 125 | 126 | | 334730 | 9487 | 127 | 128 | | 334733 | 9487 | 129 | 130 | | 334734 | 9487 | 131 | 132 | | 334735 | 9487 | 133 | 134 | | 334736 | 9487 | 135 | 136 | | 334737 | 9487 | 137 | 138 | | 334738 | 9487 | 139 | 140 | | 334739 | 9487 | 141 | 142 | | 334740 | 9487 | 143 | 144 | | 334741 | 9487 | 145 | 146 | | 334742 | 9487 | 147 | 148 | | 334743 | 9487 | 149 | 150 | | 334744 | 9487 | 151 | 152 | | 334745 | 9487 | 153 | 154 | | 334746 | 9487 | 155 | 156 | | 334747 | 9487 | 157 | 158 | | 334748 | 9487 | 159 | 160 | | 334749 | 9487 | 161 | 162 | | 334750 | 9487 | 163 | 164 | | 334751 | 9487 | 165 | 166 | | 335169 | 9487 | 167 | 168 | | 335170 | 9487 | 169 | 170 | | 335171 | 9487 | 171 | 172 | | 335172 | 9487 | 173 | 174 | | 335173 | 9487 | 175 | 176 | | 335174 | 9487 | 177 | 178 | | 9479 | NULL | 179 | 348 | | 334807 | 9479 | 180 | 189 | | 334848 | 334807 | 181 | 184 | | 334850 | 334848 | 182 | 183 | | 334928 | 334807 | 185 | 186 | | 334990 | 334807 | 187 | 188 | | 334808 | 9479 | 190 | 217 | | 334820 | 334808 | 191 | 198 | | 334985 | 334820 | 192 | 197 | | 335300 | 334985 | 193 | 196 | | 335516 | 335300 | 194 | 195 | | 334821 | 334808 | 199 | 200 | | 334846 | 334808 | 201 | 204 | | 334986 | 334846 | 202 | 203 | | 334929 | 334808 | 205 | 208 | | 334987 | 334929 | 206 | 207 | | 334978 | 334808 | 209 | 214 | | 334989 | 334978 | 210 | 213 | | 334998 | 334989 | 211 | 212 | | 335270 | 334808 | 215 | 216 | | 334809 | 9479 | 218 | 223 | | 334825 | 334809 | 219 | 220 | | 334855 | 334809 | 221 | 222 | | 334810 | 9479 | 224 | 229 | | 334980 | 334810 | 225 | 226 | | 335298 | 334810 | 227 | 228 | | 334812 | 9479 | 230 | 235 | | 334930 | 334812 | 231 | 234 | | 335249 | 334930 | 232 | 233 | | 334813 | 9479 | 236 | 243 | | 334999 | 334813 | 237 | 242 | | 335008 | 334999 | 238 | 241 | | 335293 | 335008 | 239 | 240 | | 334814 | 9479 | 244 | 247 | | 335296 | 334814 | 245 | 246 | | 334815 | 9479 | 248 | 255 | | 334856 | 334815 | 249 | 254 | | 334957 | 334856 | 250 | 253 | | 334991 | 334957 | 251 | 252 | | 334817 | 9479 | 256 | 277 | | 334827 | 334817 | 257 | 260 | | 334852 | 334827 | 258 | 259 | | 334851 | 334817 | 261 | 264 | | 334853 | 334851 | 262 | 263 | | 335271 | 334817 | 265 | 266 | | 335277 | 334817 | 267 | 272 | | 335294 | 335277 | 268 | 271 | | 335304 | 335294 | 269 | 270 | | 335302 | 334817 | 273 | 276 | | 335308 | 335302 | 274 | 275 | | 334818 | 9479 | 278 | 281 | | 334992 | 334818 | 279 | 280 | | 334819 | 9479 | 282 | 291 | | 334854 | 334819 | 283 | 284 | | 334925 | 334819 | 285 | 286 | | 334988 | 334819 | 287 | 290 | | 335309 | 334988 | 288 | 289 | | 334822 | 9479 | 292 | 297 | | 334926 | 334822 | 293 | 296 | | 335268 | 334926 | 294 | 295 | | 334823 | 9479 | 298 | 301 | | 335000 | 334823 | 299 | 300 | | 334824 | 9479 | 302 | 307 | | 334857 | 334824 | 303 | 306 | | 334979 | 334857 | 304 | 305 | | 334946 | 9479 | 308 | 313 | | 335269 | 334946 | 309 | 312 | | 335273 | 335269 | 310 | 311 | | 335192 | 9479 | 314 | 321 | | 335257 | 335192 | 315 | 320 | | 335258 | 335257 | 316 | 319 | | 335259 | 335258 | 317 | 318 | | 335193 | 9479 | 322 | 323 | | 335196 | 9479 | 324 | 327 | | 335295 | 335196 | 325 | 326 | | 335197 | 9479 | 328 | 329 | | 335198 | 9479 | 330 | 335 | | 335246 | 335198 | 331 | 332 | | 335250 | 335198 | 333 | 334 | | 335199 | 9479 | 336 | 343 | | 335272 | 335199 | 337 | 338 | | 335303 | 335199 | 339 | 342 | | 335305 | 335303 | 340 | 341 | | 335200 | 9479 | 344 | 347 | | 335299 | 335200 | 345 | 346 | | 334754 | 9481 | 348 | 361 | | 334761 | 334754 | 349 | 350 | | 334766 | 334754 | 351 | 354 | | 335181 | 334766 | 352 | 353 | | 334791 | 334754 | 355 | 356 | | 334783 | 334754 | 357 | 358 | | 335184 | 334754 | 359 | 360 | | 334755 | 9481 | 362 | 375 | | 334764 | 334755 | 363 | 372 | | 334784 | 334764 | 364 | 365 | | 334789 | 334764 | 366 | 369 | | 334796 | 334789 | 367 | 368 | | 334969 | 334764 | 370 | 371 | | 334777 | 334755 | 373 | 374 | | 334756 | 9481 | 376 | 389 | | 334767 | 334756 | 377 | 382 | | 334780 | 334767 | 378 | 381 | | 334795 | 334780 | 379 | 380 | | 334772 | 334756 | 383 | 384 | | 334773 | 334756 | 385 | 386 | | 335183 | 334756 | 387 | 388 | | 334757 | 9481 | 390 | 395 | | 334785 | 334757 | 391 | 394 | | 335179 | 334785 | 392 | 393 | | 334758 | 9481 | 396 | 397 | | 334759 | 9481 | 398 | 405 | | 334769 | 334759 | 399 | 400 | | 334776 | 334759 | 401 | 404 | | 334787 | 334776 | 402 | 403 | | 334760 | 9481 | 406 | 413 | | 334778 | 334760 | 407 | 408 | | 334781 | 334760 | 409 | 410 | | 335182 | 334760 | 411 | 412 | | 334762 | 9481 | 414 | 417 | | 334954 | 334762 | 415 | 416 | | 334763 | 9481 | 418 | 423 | | 334786 | 334763 | 419 | 420 | | 334794 | 334763 | 421 | 422 | | 334765 | 9481 | 424 | 427 | | 334782 | 334765 | 425 | 426 | | 334768 | 9481 | 428 | 431 | | 334968 | 334768 | 429 | 430 | | 334770 | 9481 | 432 | 435 | | 334973 | 334770 | 433 | 434 | | 334771 | 9481 | 436 | 443 | | 334799 | 334771 | 437 | 440 | | 334967 | 334799 | 438 | 439 | | 334982 | 334771 | 441 | 442 | | 334774 | 9481 | 444 | 449 | | 334788 | 334774 | 445 | 446 | | 334792 | 334774 | 447 | 448 | | 334775 | 9481 | 450 | 461 | | 334797 | 334775 | 451 | 454 | | 334887 | 334797 | 452 | 453 | | 334798 | 334775 | 455 | 458 | | 334894 | 334798 | 456 | 457 | | 335180 | 334775 | 459 | 460 | | 334779 | 9481 | 462 | 463 | | 334790 | 9481 | 464 | 469 | | 334897 | 334790 | 465 | 466 | | 334981 | 334790 | 467 | 468 | | 335175 | 9481 | 470 | 471 | | 335176 | 9481 | 472 | 473 | | 335177 | 9481 | 474 | 475 | | 335178 | 9481 | 476 | 477 | | 9488 | NULL | 478 | 515 | | 334828 | 9488 | 479 | 480 | | 334829 | 9488 | 481 | 482 | | 334830 | 9488 | 483 | 484 | | 334831 | 9488 | 485 | 486 | | 334832 | 9488 | 487 | 488 | | 334833 | 9488 | 489 | 490 | | 334834 | 9488 | 491 | 492 | | 334835 | 9488 | 493 | 494 | | 334836 | 9488 | 495 | 496 | | 334837 | 9488 | 497 | 498 | | 334838 | 9488 | 499 | 500 | | 334839 | 9488 | 501 | 502 | | 334840 | 9488 | 503 | 504 | | 334841 | 9488 | 505 | 506 | | 334842 | 9488 | 507 | 508 | | 334843 | 9488 | 509 | 510 | | 334844 | 9488 | 511 | 512 | | 334845 | 9488 | 513 | 514 | | 9482 | NULL | 515 | 520 | | 334933 | 9482 | 516 | 517 | | 334993 | 9482 | 518 | 519 | | 9483 | NULL | 520 | 525 | | 334935 | 9483 | 521 | 522 | | 334995 | 9483 | 523 | 524 | | 9484 | NULL | 525 | 526 | | 9485 | NULL | 526 | 579 | | 334713 | 9485 | 527 | 528 | | 334714 | 9485 | 529 | 530 | | 334715 | 9485 | 531 | 532 | | 334716 | 9485 | 533 | 536 | | 334728 | 334716 | 534 | 535 | | 334717 | 9485 | 537 | 538 | | 334718 | 9485 | 539 | 540 | | 334719 | 9485 | 541 | 542 | | 334720 | 9485 | 543 | 544 | | 334721 | 9485 | 545 | 546 | | 334722 | 9485 | 547 | 548 | | 334723 | 9485 | 549 | 550 | | 334724 | 9485 | 551 | 552 | | 334725 | 9485 | 553 | 554 | | 334726 | 9485 | 555 | 556 | | 334727 | 9485 | 557 | 558 | | 334976 | 9485 | 559 | 560 | | 334983 | 9485 | 561 | 562 | | 334996 | 9485 | 563 | 564 | | 334997 | 9485 | 565 | 566 | | 335163 | 9485 | 567 | 568 | | 335164 | 9485 | 569 | 570 | | 335165 | 9485 | 571 | 572 | | 335166 | 9485 | 573 | 574 | | 335167 | 9485 | 575 | 576 | | 335168 | 9485 | 577 | 578 | | 334881 | NULL | 579 | 580 | | 335201 | NULL | 581 | 584 | | 335310 | 335201 | 582 | 583 | | 335234 | NULL | 585 | 586 | +--------+-----------+------+------+ 300 rows in set (0.30 sec) From rogishmn at muohio.edu Tue Aug 14 14:46:31 2007 From: rogishmn at muohio.edu (Matt Rogish) Date: Tue, 14 Aug 2007 14:46:31 -0400 Subject: [Betternestedset-talk] Concurrency issues? In-Reply-To: <8d64b97d0708141121i4430f4e5jea5aeab2bb7176df@mail.gmail.com> References: <46C1EA4E.7000707@goldnoteexpress.com> <8d64b97d0708141121i4430f4e5jea5aeab2bb7176df@mail.gmail.com> Message-ID: Hi Krishna, I have no move code (moving is not allowed! :D), my delete code is fairly straightforward: def destroy m = Message.find(params[:id]) #security check to make sure they can delete snipped m.destroy redirect_back_or_default :controller => :message_boards, :action => :show, :id => @current_message_board end All tables are innodb_tables: SHOW CREATE TABLE messages; CREATE TABLE `messages` ( ... ) ENGINE=InnoDB -- Matt On 8/14/07, Krishna Dole wrote: > > Hi Matt, > > Is this the only code you have that alters the tree? Any delete/move > code? Also, are you using a transactional storage engine? (basically > anything other than MyISAM, I think). > > I presume the message_board_id is being set from params[:message]. > > Krishna > > On 8/14/07, Matt Rogish wrote: > > I'm not writing any SQL, I'm using built-in better-nested-set functions. > > > > Here's my save: > > def create > > @message = Message.new(params[:message]) > > > > if @message.save > > flash[:notice] = 'Message was successfully created.' > > > > if params[:message][:parent_id] > > @message.move_to_child_of( Message.findparams[:message][:parent_id] > > ) > > @message.save > > end > > end > > end > > > > -- > > Matt > > > > > > > > On 8/14/07, Jeremy Nicoll wrote: > > > > > > I think it would be best if you could post your SQL that is messed > up > > as well as the code you are using to save your nodes. Unfortunately we > > can't tell you what is wrong until we actually see the logic behind what > you > > are doing. > > > > > > -- > > > Jeremy Nicoll > > > > > > Matt Rogish wrote: > > > > > > How can I repair my tree? > > > > > > I have a message board system in which the messages are grouped by > > "message_board_id", thus my model is: > > > acts_as_nested_set :scope => :message_board_id > > > > > > Somehow the tree is messed up, inasmuch as some roots (parent_id == > null) > > are being set to the children of some other message, so I cannot > > successfully repair it. I'm not sure if I'm performing incorrect > operations > > or what, but somehow I need to repair my tree where message_board_id = > 34 > > (or whatever it is). > > > > > > It seems as if renumber_full_tree tries to find the virtual root for a > > given node, but since the root itself is a CHILD of another node, the > whole > > thing fails. My layman's guess is that the "root" condition is wrong, > since > > it's doing WHERE parent_id IS NULL ... AND lft BETWEEN .. AND .. > > > > > > Well, if the root is incorrectly between something, then the lft would > > fail, no? Maybe I'm misreading that. Help!! > > > > > > Thanks, > > > > > > -- > > > Matt > > > > > > > > > On 8/14/07, Matt Rogish wrote: > > > > Under heavy load we are getting significantly screwed up data. I > have to > > run renumber_full_tree in script/console production order to repair the > > thing. > > > > > > > > Obviously this is a bad thing, but I don't even know where to start > to > > fix it. Any ideas? > > > > > > > > Thanks, > > > > > > > > -- > > > > Matt > > > > > > > > > > ________________________________ > > > > > _______________________________________________ > > > Betternestedset-talk mailing list > > > Betternestedset-talk at rubyforge.org > > > > > > > > > > > http://rubyforge.org/mailman/listinfo/betternestedset-talk > > > > > > > > > _______________________________________________ > > > Betternestedset-talk mailing list > > > Betternestedset-talk at rubyforge.org > > > > > http://rubyforge.org/mailman/listinfo/betternestedset-talk > > > > > > > > > > > > _______________________________________________ > > Betternestedset-talk mailing list > > Betternestedset-talk at rubyforge.org > > http://rubyforge.org/mailman/listinfo/betternestedset-talk > > > > > _______________________________________________ > Betternestedset-talk mailing list > Betternestedset-talk at rubyforge.org > http://rubyforge.org/mailman/listinfo/betternestedset-talk > -------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/betternestedset-talk/attachments/20070814/3c7b390f/attachment.html From rogishmn at muohio.edu Tue Aug 14 15:23:52 2007 From: rogishmn at muohio.edu (Matt Rogish) Date: Tue, 14 Aug 2007 15:23:52 -0400 Subject: [Betternestedset-talk] Concurrency issues? In-Reply-To: References: <46C1EA4E.7000707@goldnoteexpress.com> Message-ID: My guess is that there's a bug in the implementation of renumber_full_tree/calc_numbers which is causing this problem. The dataset with overlapping numbers is what resulted from applying renumber_full_tree; thus something is not quite right with that method... I have a copy of SQL for Smarties (2nd ed), so I'll try and see if the two algorithms diverge at all and/or provide a patch if I can help it. :) Thanks, -- Matt On 8/14/07, Matt Rogish wrote: > > The problem is, as I see it, overlapping left and right columns. Shouldn't > the lft/right be one apart, or am I wrong. > > For example: > mysql> select id, parent_id, lft, rgt from messages where message_board_id > = 1926 and parent_id is null order by lft; > +--------+-----------+------+------+ > | id | parent_id | lft | rgt | > +--------+-----------+------+------+ > | 9472 | NULL | 1 | 2 | > | 9473 | NULL | 2 | 37 | > | 9474 | NULL | 37 | 44 | > | 9475 | NULL | 44 | 45 | > | 9476 | NULL | 45 | 74 | > | 9477 | NULL | 74 | 75 | > | 9478 | NULL | 75 | 114 | > | 9487 | NULL | 114 | 179 | > | 9479 | NULL | 179 | 348 | > | 9488 | NULL | 478 | 515 | > | 9482 | NULL | 515 | 520 | > | 9483 | NULL | 520 | 525 | > | 9484 | NULL | 525 | 526 | > | 9485 | NULL | 526 | 579 | > | 334881 | NULL | 579 | 580 | > | 335201 | NULL | 581 | 584 | > | 335234 | NULL | 585 | 586 | > +--------+-----------+------+------+ > > So the only ones "correct" are id = 335201 and id = 335234? > > I attached the entire dataset. What is happening is that the BETWEEN > statement that better nested set is executing looks something like this: > m = Message.find( 9478 ) > m.all_children.each{ stuff } > > SQL is: > SELECT * FROM messages WHERE (message_board_id = 1926 AND (lft BETWEEN 75 > AND 114)) ORDER BY lf > > Since BETWEEN is inclusive, that result pulls all the children correctly > but incorrectly pulls out the next root, message id = 9487. > > I'm not sure if that means renumber_entire_tree needs to be fixed, or the > actual move_to_child does, but something isn't right. > > -- > Matt > > On 8/14/07, Matt Rogish wrote: > > > > I'm not writing any SQL, I'm using built-in better-nested-set functions. > > > > Here's my save: > > def create > > @message = Message.new(params[:message]) > > > > if @message.save > > flash[:notice] = 'Message was successfully created.' > > > > if params[:message][:parent_id] > > @message.move_to_child_of( Message.findparams[:message][:parent_id] ) > > @message.save > > end > > end > > end > > > > -- > > Matt > > > > On 8/14/07, Jeremy Nicoll wrote: > > > > > > I think it would be best if you could post your SQL that is > > > messed up as well as the code you are using to save your nodes. > > > Unfortunately we can't tell you what is wrong until we actually see the > > > logic behind what you are doing. > > > > > > -- > > > Jeremy Nicoll > > > > > > Matt Rogish wrote: > > > > > > How can I repair my tree? > > > > > > I have a message board system in which the messages are grouped by > > > "message_board_id", thus my model is: > > > acts_as_nested_set :scope => :message_board_id > > > > > > Somehow the tree is messed up, inasmuch as some roots (parent_id == > > > null) are being set to the children of some other message, so I cannot > > > successfully repair it. I'm not sure if I'm performing incorrect operations > > > or what, but somehow I need to repair my tree where message_board_id = 34 > > > (or whatever it is). > > > > > > It seems as if renumber_full_tree tries to find the virtual root for a > > > given node, but since the root itself is a CHILD of another node, the whole > > > thing fails. My layman's guess is that the "root" condition is wrong, since > > > it's doing WHERE parent_id IS NULL ... AND lft BETWEEN .. AND .. > > > > > > Well, if the root is incorrectly between something, then the lft would > > > fail, no? Maybe I'm misreading that. Help!! > > > > > > Thanks, > > > > > > -- > > > Matt > > > > > > On 8/14/07, Matt Rogish wrote: > > > > > > > > Under heavy load we are getting significantly screwed up data. I > > > > have to run renumber_full_tree in script/console production order to repair > > > > the thing. > > > > > > > > Obviously this is a bad thing, but I don't even know where to start > > > > to fix it. Any ideas? > > > > > > > > Thanks, > > > > > > > > -- > > > > Matt > > > > > > > > > > ------------------------------ > > > > > > _______________________________________________ > > > Betternestedset-talk mailing list > > > Betternestedset-talk at rubyforge.org > > > > > > > > > http://rubyforge.org/mailman/listinfo/betternestedset-talk > > > > > > > > > _______________________________________________ > > > Betternestedset-talk mailing list > > > Betternestedset-talk at rubyforge.org > > > http://rubyforge.org/mailman/listinfo/betternestedset-talk > > > > > > > > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/betternestedset-talk/attachments/20070814/ccaa421f/attachment-0001.html From dontfall at gmail.com Tue Aug 14 15:57:51 2007 From: dontfall at gmail.com (Krishna Dole) Date: Tue, 14 Aug 2007 15:57:51 -0400 Subject: [Betternestedset-talk] Concurrency issues? In-Reply-To: References: <46C1EA4E.7000707@goldnoteexpress.com> Message-ID: <8d64b97d0708141257o4bc6d348j8241255885ef32c0@mail.gmail.com> Hey Matt, You were right-- there was a bug in the renumbering when working with virtual roots. I have fixed it in trunk. You can get the fixed version with script/plugin install svn://rubyforge.org/var/svn/betternestedset/trunk Thanks for reporting this. Krishna On 8/14/07, Matt Rogish wrote: > My guess is that there's a bug in the implementation of > renumber_full_tree/calc_numbers which is causing this problem. The dataset > with overlapping numbers is what resulted from applying renumber_full_tree; > thus something is not quite right with that method... > > I have a copy of SQL for Smarties (2nd ed), so I'll try and see if the two > algorithms diverge at all and/or provide a patch if I can help it. :) > > Thanks, > > -- > Matt > > > On 8/14/07, Matt Rogish wrote: > > > > The problem is, as I see it, overlapping left and right columns. Shouldn't > the lft/right be one apart, or am I wrong. > > > > For example: > > mysql> select id, parent_id, lft, rgt from messages where message_board_id > = 1926 and parent_id is null order by lft; > > +--------+-----------+------+------+ > > | id | parent_id | lft | rgt | > > +--------+-----------+------+------+ > > | 9472 | NULL | 1 | 2 | > > | 9473 | NULL | 2 | 37 | > > | 9474 | NULL | 37 | 44 | > > | 9475 | NULL | 44 | 45 | > > | 9476 | NULL | 45 | 74 | > > | 9477 | NULL | 74 | 75 | > > | 9478 | NULL | 75 | 114 | > > | 9487 | NULL | 114 | 179 | > > | 9479 | NULL | 179 | 348 | > > | 9488 | NULL | 478 | 515 | > > | 9482 | NULL | 515 | 520 | > > | 9483 | NULL | 520 | 525 | > > | 9484 | NULL | 525 | 526 | > > | 9485 | NULL | 526 | 579 | > > | 334881 | NULL | 579 | 580 | > > | 335201 | NULL | 581 | 584 | > > | 335234 | NULL | 585 | 586 | > > +--------+-----------+------+------+ > > > > So the only ones "correct" are id = 335201 and id = 335234? > > > > I attached the entire dataset. What is happening is that the BETWEEN > statement that better nested set is executing looks something like this: > > m = Message.find( 9478 ) > > m.all_children.each{ stuff } > > > > SQL is: > > SELECT * FROM messages WHERE (message_board_id = 1926 AND (lft BETWEEN 75 > AND 114)) ORDER BY lf > > > > Since BETWEEN is inclusive, that result pulls all the children correctly > but incorrectly pulls out the next root, message id = 9487. > > > > I'm not sure if that means renumber_entire_tree needs to be fixed, or the > actual move_to_child does, but something isn't right. > > > > > > -- > > > > Matt > > > > > > On 8/14/07, Matt Rogish wrote: > > > I'm not writing any SQL, I'm using built-in better-nested-set functions. > > > > > > Here's my save: > > > def create > > > @message = Message.new(params[:message]) > > > > > > if @message.save > > > flash[:notice] = 'Message was successfully created.' > > > > > > if params[:message][:parent_id] > > > @message.move_to_child_of( Message.find > params[:message][:parent_id] ) > > > @message.save > > > end > > > end > > > end > > > > > > -- > > > Matt > > > > > > > > > > > > On 8/14/07, Jeremy Nicoll wrote: > > > > > > > > I think it would be best if you could post your SQL that is messed > up as well as the code you are using to save your nodes. Unfortunately we > can't tell you what is wrong until we actually see the logic behind what you > are doing. > > > > > > > > -- > > > > Jeremy Nicoll > > > > > > > > Matt Rogish wrote: > > > > > > > > How can I repair my tree? > > > > > > > > I have a message board system in which the messages are grouped by > "message_board_id", thus my model is: > > > > acts_as_nested_set :scope => :message_board_id > > > > > > > > Somehow the tree is messed up, inasmuch as some roots (parent_id == > null) are being set to the children of some other message, so I cannot > successfully repair it. I'm not sure if I'm performing incorrect operations > or what, but somehow I need to repair my tree where message_board_id = 34 > (or whatever it is). > > > > > > > > It seems as if renumber_full_tree tries to find the virtual root for a > given node, but since the root itself is a CHILD of another node, the whole > thing fails. My layman's guess is that the "root" condition is wrong, since > it's doing WHERE parent_id IS NULL ... AND lft BETWEEN .. AND .. > > > > > > > > Well, if the root is incorrectly between something, then the lft would > fail, no? Maybe I'm misreading that. Help!! > > > > > > > > Thanks, > > > > > > > > -- > > > > Matt > > > > > > > > > > > > On 8/14/07, Matt Rogish wrote: > > > > > Under heavy load we are getting significantly screwed up data. I > have to run renumber_full_tree in script/console production order to repair > the thing. > > > > > > > > > > Obviously this is a bad thing, but I don't even know where to start > to fix it. Any ideas? > > > > > > > > > > Thanks, > > > > > > > > > > -- > > > > > Matt > > > > > > > > > > > > > ________________________________ > > > > > _______________________________________________ > > > > Betternestedset-talk mailing list > > > > Betternestedset-talk at rubyforge.org > > > > > > > > > > > > > > > > > > > > > http://rubyforge.org/mailman/listinfo/betternestedset-talk > > > > > > > > > > > > _______________________________________________ > > > > Betternestedset-talk mailing list > > > > Betternestedset-talk at rubyforge.org > > > > > http://rubyforge.org/mailman/listinfo/betternestedset-talk > > > > > > > > > > > > > > > > > > > > > > > _______________________________________________ > Betternestedset-talk mailing list > Betternestedset-talk at rubyforge.org > http://rubyforge.org/mailman/listinfo/betternestedset-talk > > From jnicoll at goldnoteexpress.com Tue Aug 14 16:12:02 2007 From: jnicoll at goldnoteexpress.com (Jeremy Nicoll) Date: Tue, 14 Aug 2007 14:12:02 -0600 Subject: [Betternestedset-talk] Concurrency issues? In-Reply-To: <8d64b97d0708141257o4bc6d348j8241255885ef32c0@mail.gmail.com> References: <46C1EA4E.7000707@goldnoteexpress.com> <8d64b97d0708141257o4bc6d348j8241255885ef32c0@mail.gmail.com> Message-ID: <46C20C92.9070601@goldnoteexpress.com> Thanks Matt - I'm glad you found this before my app went to production :). Good luck with yours. -- Jeremy Nicoll Krishna Dole wrote: > Hey Matt, > > You were right-- there was a bug in the renumbering when working with > virtual roots. I have fixed it in trunk. You can get the fixed version > with > > script/plugin install svn://rubyforge.org/var/svn/betternestedset/trunk > > Thanks for reporting this. > > Krishna > > On 8/14/07, Matt Rogish wrote: > >> My guess is that there's a bug in the implementation of >> renumber_full_tree/calc_numbers which is causing this problem. The dataset >> with overlapping numbers is what resulted from applying renumber_full_tree; >> thus something is not quite right with that method... >> >> I have a copy of SQL for Smarties (2nd ed), so I'll try and see if the two >> algorithms diverge at all and/or provide a patch if I can help it. :) >> >> Thanks, >> >> -- >> Matt >> >> >> On 8/14/07, Matt Rogish wrote: >> >>> The problem is, as I see it, overlapping left and right columns. Shouldn't >>> >> the lft/right be one apart, or am I wrong. >> >>> For example: >>> mysql> select id, parent_id, lft, rgt from messages where message_board_id >>> >> = 1926 and parent_id is null order by lft; >> >>> +--------+-----------+------+------+ >>> | id | parent_id | lft | rgt | >>> +--------+-----------+------+------+ >>> | 9472 | NULL | 1 | 2 | >>> | 9473 | NULL | 2 | 37 | >>> | 9474 | NULL | 37 | 44 | >>> | 9475 | NULL | 44 | 45 | >>> | 9476 | NULL | 45 | 74 | >>> | 9477 | NULL | 74 | 75 | >>> | 9478 | NULL | 75 | 114 | >>> | 9487 | NULL | 114 | 179 | >>> | 9479 | NULL | 179 | 348 | >>> | 9488 | NULL | 478 | 515 | >>> | 9482 | NULL | 515 | 520 | >>> | 9483 | NULL | 520 | 525 | >>> | 9484 | NULL | 525 | 526 | >>> | 9485 | NULL | 526 | 579 | >>> | 334881 | NULL | 579 | 580 | >>> | 335201 | NULL | 581 | 584 | >>> | 335234 | NULL | 585 | 586 | >>> +--------+-----------+------+------+ >>> >>> So the only ones "correct" are id = 335201 and id = 335234? >>> >>> I attached the entire dataset. What is happening is that the BETWEEN >>> >> statement that better nested set is executing looks something like this: >> >>> m = Message.find( 9478 ) >>> m.all_children.each{ stuff } >>> >>> SQL is: >>> SELECT * FROM messages WHERE (message_board_id = 1926 AND (lft BETWEEN 75 >>> >> AND 114)) ORDER BY lf >> >>> Since BETWEEN is inclusive, that result pulls all the children correctly >>> >> but incorrectly pulls out the next root, message id = 9487. >> >>> I'm not sure if that means renumber_entire_tree needs to be fixed, or the >>> >> actual move_to_child does, but something isn't right. >> >>> -- >>> >>> Matt >>> >>> >>> On 8/14/07, Matt Rogish wrote: >>> >>>> I'm not writing any SQL, I'm using built-in better-nested-set functions. >>>> >>>> Here's my save: >>>> def create >>>> @message = Message.new(params[:message]) >>>> >>>> if @message.save >>>> flash[:notice] = 'Message was successfully created.' >>>> >>>> if params[:message][:parent_id] >>>> @message.move_to_child_of( Message.find >>>> >> params[:message][:parent_id] ) >> >>>> @message.save >>>> end >>>> end >>>> end >>>> >>>> -- >>>> Matt >>>> >>>> >>>> >>>> On 8/14/07, Jeremy Nicoll wrote: >>>> >>>>> I think it would be best if you could post your SQL that is messed >>>>> >> up as well as the code you are using to save your nodes. Unfortunately we >> can't tell you what is wrong until we actually see the logic behind what you >> are doing. >> >>>>> -- >>>>> Jeremy Nicoll >>>>> >>>>> Matt Rogish wrote: >>>>> >>>>> How can I repair my tree? >>>>> >>>>> I have a message board system in which the messages are grouped by >>>>> >> "message_board_id", thus my model is: >> >>>>> acts_as_nested_set :scope => :message_board_id >>>>> >>>>> Somehow the tree is messed up, inasmuch as some roots (parent_id == >>>>> >> null) are being set to the children of some other message, so I cannot >> successfully repair it. I'm not sure if I'm performing incorrect operations >> or what, but somehow I need to repair my tree where message_board_id = 34 >> (or whatever it is). >> >>>>> It seems as if renumber_full_tree tries to find the virtual root for a >>>>> >> given node, but since the root itself is a CHILD of another node, the whole >> thing fails. My layman's guess is that the "root" condition is wrong, since >> it's doing WHERE parent_id IS NULL ... AND lft BETWEEN .. AND .. >> >>>>> Well, if the root is incorrectly between something, then the lft would >>>>> >> fail, no? Maybe I'm misreading that. Help!! >> >>>>> Thanks, >>>>> >>>>> -- >>>>> Matt >>>>> >>>>> >>>>> On 8/14/07, Matt Rogish wrote: >>>>> >>>>>> Under heavy load we are getting significantly screwed up data. I >>>>>> >> have to run renumber_full_tree in script/console production order to repair >> the thing. >> >>>>>> Obviously this is a bad thing, but I don't even know where to start >>>>>> >> to fix it. Any ideas? >> >>>>>> Thanks, >>>>>> >>>>>> -- >>>>>> Matt >>>>>> >>>>>> >>>>> ________________________________ >>>>> >>>>> _______________________________________________ >>>>> Betternestedset-talk mailing list >>>>> Betternestedset-talk at rubyforge.org >>>>> >>>>> >>>>> >>>>> >>>>> >>>>> >> http://rubyforge.org/mailman/listinfo/betternestedset-talk >> >>>>> _______________________________________________ >>>>> Betternestedset-talk mailing list >>>>> Betternestedset-talk at rubyforge.org >>>>> >>>>> >> http://rubyforge.org/mailman/listinfo/betternestedset-talk >> >>>>> >>>> >>> >>> >> _______________________________________________ >> Betternestedset-talk mailing list >> Betternestedset-talk at rubyforge.org >> http://rubyforge.org/mailman/listinfo/betternestedset-talk >> >> >> > _______________________________________________ > Betternestedset-talk mailing list > Betternestedset-talk at rubyforge.org > http://rubyforge.org/mailman/listinfo/betternestedset-talk > > -------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/betternestedset-talk/attachments/20070814/bb490db3/attachment.html From rogishmn at muohio.edu Tue Aug 14 17:50:05 2007 From: rogishmn at muohio.edu (Matt Rogish) Date: Tue, 14 Aug 2007 17:50:05 -0400 Subject: [Betternestedset-talk] Concurrency issues? In-Reply-To: <8d64b97d0708141257o4bc6d348j8241255885ef32c0@mail.gmail.com> References: <46C1EA4E.7000707@goldnoteexpress.com> <8d64b97d0708141257o4bc6d348j8241255885ef32c0@mail.gmail.com> Message-ID: Krishna, That worked GREAT! Thanks for such a wonderful library! :D Thanks, -- Matt On 8/14/07, Krishna Dole wrote: > > Hey Matt, > > You were right-- there was a bug in the renumbering when working with > virtual roots. I have fixed it in trunk. You can get the fixed version > with > > script/plugin install svn://rubyforge.org/var/svn/betternestedset/trunk > > Thanks for reporting this. > > Krishna > > On 8/14/07, Matt Rogish wrote: > > My guess is that there's a bug in the implementation of > > renumber_full_tree/calc_numbers which is causing this problem. The > dataset > > with overlapping numbers is what resulted from applying > renumber_full_tree; > > thus something is not quite right with that method... > > > > I have a copy of SQL for Smarties (2nd ed), so I'll try and see if the > two > > algorithms diverge at all and/or provide a patch if I can help it. :) > > > > Thanks, > > > > -- > > Matt > > > > > > On 8/14/07, Matt Rogish wrote: > > > > > > The problem is, as I see it, overlapping left and right columns. > Shouldn't > > the lft/right be one apart, or am I wrong. > > > > > > For example: > > > mysql> select id, parent_id, lft, rgt from messages where > message_board_id > > = 1926 and parent_id is null order by lft; > > > +--------+-----------+------+------+ > > > | id | parent_id | lft | rgt | > > > +--------+-----------+------+------+ > > > | 9472 | NULL | 1 | 2 | > > > | 9473 | NULL | 2 | 37 | > > > | 9474 | NULL | 37 | 44 | > > > | 9475 | NULL | 44 | 45 | > > > | 9476 | NULL | 45 | 74 | > > > | 9477 | NULL | 74 | 75 | > > > | 9478 | NULL | 75 | 114 | > > > | 9487 | NULL | 114 | 179 | > > > | 9479 | NULL | 179 | 348 | > > > | 9488 | NULL | 478 | 515 | > > > | 9482 | NULL | 515 | 520 | > > > | 9483 | NULL | 520 | 525 | > > > | 9484 | NULL | 525 | 526 | > > > | 9485 | NULL | 526 | 579 | > > > | 334881 | NULL | 579 | 580 | > > > | 335201 | NULL | 581 | 584 | > > > | 335234 | NULL | 585 | 586 | > > > +--------+-----------+------+------+ > > > > > > So the only ones "correct" are id = 335201 and id = 335234? > > > > > > I attached the entire dataset. What is happening is that the BETWEEN > > statement that better nested set is executing looks something like this: > > > m = Message.find( 9478 ) > > > m.all_children.each{ stuff } > > > > > > SQL is: > > > SELECT * FROM messages WHERE (message_board_id = 1926 AND (lft BETWEEN > 75 > > AND 114)) ORDER BY lf > > > > > > Since BETWEEN is inclusive, that result pulls all the children > correctly > > but incorrectly pulls out the next root, message id = 9487. > > > > > > I'm not sure if that means renumber_entire_tree needs to be fixed, or > the > > actual move_to_child does, but something isn't right. > > > > > > > > > -- > > > > > > Matt > > > > > > > > > On 8/14/07, Matt Rogish wrote: > > > > I'm not writing any SQL, I'm using built-in better-nested-set > functions. > > > > > > > > Here's my save: > > > > def create > > > > @message = Message.new(params[:message]) > > > > > > > > if @message.save > > > > flash[:notice] = 'Message was successfully created.' > > > > > > > > if params[:message][:parent_id] > > > > @message.move_to_child_of( Message.find > > params[:message][:parent_id] ) > > > > @message.save > > > > end > > > > end > > > > end > > > > > > > > -- > > > > Matt > > > > > > > > > > > > > > > > On 8/14/07, Jeremy Nicoll wrote: > > > > > > > > > > I think it would be best if you could post your SQL that is > messed > > up as well as the code you are using to save your nodes. Unfortunately > we > > can't tell you what is wrong until we actually see the logic behind what > you > > are doing. > > > > > > > > > > -- > > > > > Jeremy Nicoll > > > > > > > > > > Matt Rogish wrote: > > > > > > > > > > How can I repair my tree? > > > > > > > > > > I have a message board system in which the messages are grouped by > > "message_board_id", thus my model is: > > > > > acts_as_nested_set :scope => :message_board_id > > > > > > > > > > Somehow the tree is messed up, inasmuch as some roots (parent_id > == > > null) are being set to the children of some other message, so I cannot > > successfully repair it. I'm not sure if I'm performing incorrect > operations > > or what, but somehow I need to repair my tree where message_board_id = > 34 > > (or whatever it is). > > > > > > > > > > It seems as if renumber_full_tree tries to find the virtual root > for a > > given node, but since the root itself is a CHILD of another node, the > whole > > thing fails. My layman's guess is that the "root" condition is wrong, > since > > it's doing WHERE parent_id IS NULL ... AND lft BETWEEN .. AND .. > > > > > > > > > > Well, if the root is incorrectly between something, then the lft > would > > fail, no? Maybe I'm misreading that. Help!! > > > > > > > > > > Thanks, > > > > > > > > > > -- > > > > > Matt > > > > > > > > > > > > > > > On 8/14/07, Matt Rogish wrote: > > > > > > Under heavy load we are getting significantly screwed up data. I > > have to run renumber_full_tree in script/console production order to > repair > > the thing. > > > > > > > > > > > > Obviously this is a bad thing, but I don't even know where to > start > > to fix it. Any ideas? > > > > > > > > > > > > Thanks, > > > > > > > > > > > > -- > > > > > > Matt > > > > > > > > > > > > > > > > ________________________________ > > > > > > > _______________________________________________ > > > > > Betternestedset-talk mailing list > > > > > Betternestedset-talk at rubyforge.org > > > > > > > > > > > > > > > > > > > > > > > > > > > http://rubyforge.org/mailman/listinfo/betternestedset-talk > > > > > > > > > > > > > > > _______________________________________________ > > > > > Betternestedset-talk mailing list > > > > > Betternestedset-talk at rubyforge.org > > > > > > > http://rubyforge.org/mailman/listinfo/betternestedset-talk > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > _______________________________________________ > > Betternestedset-talk mailing list > > Betternestedset-talk at rubyforge.org > > http://rubyforge.org/mailman/listinfo/betternestedset-talk > > > > > _______________________________________________ > Betternestedset-talk mailing list > Betternestedset-talk at rubyforge.org > http://rubyforge.org/mailman/listinfo/betternestedset-talk > -------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/betternestedset-talk/attachments/20070814/22069b7e/attachment-0001.html From dontfall at gmail.com Tue Aug 14 19:53:00 2007 From: dontfall at gmail.com (Krishna Dole) Date: Tue, 14 Aug 2007 19:53:00 -0400 Subject: [Betternestedset-talk] Concurrency issues? In-Reply-To: References: <46C1EA4E.7000707@goldnoteexpress.com> <8d64b97d0708141257o4bc6d348j8241255885ef32c0@mail.gmail.com> Message-ID: <8d64b97d0708141653y49910e22s897cf3e6e0906a7e@mail.gmail.com> Hi Matt, Glad that worked. It still doesn't answer your original question about the data becoming corrupted in the first place. I don't see anything in your code that should cause problems. If you are ever able to replicate the data corruption please let us know, since Better Nested Set should be completely concurrency-safe. Krishna On 8/14/07, Matt Rogish wrote: > Krishna, > > That worked GREAT! Thanks for such a wonderful library! :D > > Thanks, > > -- > Matt > > On 8/14/07, Krishna Dole < dontfall at gmail.com> wrote: > > Hey Matt, > > > > You were right-- there was a bug in the renumbering when working with > > virtual roots. I have fixed it in trunk. You can get the fixed version > > with > > > > script/plugin install > svn://rubyforge.org/var/svn/betternestedset/trunk > > > > Thanks for reporting this. > > > > Krishna > > > > On 8/14/07, Matt Rogish < rogishmn at muohio.edu> wrote: > > > My guess is that there's a bug in the implementation of > > > renumber_full_tree/calc_numbers which is causing this problem. The > dataset > > > with overlapping numbers is what resulted from applying > renumber_full_tree; > > > thus something is not quite right with that method... > > > > > > I have a copy of SQL for Smarties (2nd ed), so I'll try and see if the > two > > > algorithms diverge at all and/or provide a patch if I can help it. :) > > > > > > Thanks, > > > > > > -- > > > Matt > > > > > > > > > On 8/14/07, Matt Rogish < matt.rogish at gmail.com> wrote: > > > > > > > > The problem is, as I see it, overlapping left and right columns. > Shouldn't > > > the lft/right be one apart, or am I wrong. > > > > > > > > For example: > > > > mysql> select id, parent_id, lft, rgt from messages where > message_board_id > > > = 1926 and parent_id is null order by lft; > > > > +--------+-----------+------+------+ > > > > | id | parent_id | lft | rgt | > > > > +--------+-----------+------+------+ > > > > | 9472 | NULL | 1 | 2 | > > > > | 9473 | NULL | 2 | 37 | > > > > | 9474 | NULL | 37 | 44 | > > > > | 9475 | NULL | 44 | 45 | > > > > | 9476 | NULL | 45 | 74 | > > > > | 9477 | NULL | 74 | 75 | > > > > | 9478 | NULL | 75 | 114 | > > > > | 9487 | NULL | 114 | 179 | > > > > | 9479 | NULL | 179 | 348 | > > > > | 9488 | NULL | 478 | 515 | > > > > | 9482 | NULL | 515 | 520 | > > > > | 9483 | NULL | 520 | 525 | > > > > | 9484 | NULL | 525 | 526 | > > > > | 9485 | NULL | 526 | 579 | > > > > | 334881 | NULL | 579 | 580 | > > > > | 335201 | NULL | 581 | 584 | > > > > | 335234 | NULL | 585 | 586 | > > > > +--------+-----------+------+------+ > > > > > > > > So the only ones "correct" are id = 335201 and id = 335234? > > > > > > > > I attached the entire dataset. What is happening is that the BETWEEN > > > statement that better nested set is executing looks something like this: > > > > m = Message.find( 9478 ) > > > > m.all_children.each{ stuff } > > > > > > > > SQL is: > > > > SELECT * FROM messages WHERE (message_board_id = 1926 AND (lft BETWEEN > 75 > > > AND 114)) ORDER BY lf > > > > > > > > Since BETWEEN is inclusive, that result pulls all the children > correctly > > > but incorrectly pulls out the next root, message id = 9487. > > > > > > > > I'm not sure if that means renumber_entire_tree needs to be fixed, or > the > > > actual move_to_child does, but something isn't right. > > > > > > > > > > > > -- > > > > > > > > Matt > > > > > > > > > > > > On 8/14/07, Matt Rogish wrote: > > > > > I'm not writing any SQL, I'm using built-in better-nested-set > functions. > > > > > > > > > > Here's my save: > > > > > def create > > > > > @message = Message.new(params[:message]) > > > > > > > > > > if @message.save > > > > > flash[:notice] = 'Message was successfully created.' > > > > > > > > > > if params[:message][:parent_id] > > > > > @message.move_to_child_of( Message.find > > > params[:message][:parent_id] ) > > > > > @message.save > > > > > end > > > > > end > > > > > end > > > > > > > > > > -- > > > > > Matt > > > > > > > > > > > > > > > > > > > > On 8/14/07, Jeremy Nicoll < jnicoll at goldnoteexpress.com > wrote: > > > > > > > > > > > > I think it would be best if you could post your SQL that is > messed > > > up as well as the code you are using to save your nodes. Unfortunately > we > > > can't tell you what is wrong until we actually see the logic behind what > you > > > are doing. > > > > > > > > > > > > -- > > > > > > Jeremy Nicoll > > > > > > > > > > > > Matt Rogish wrote: > > > > > > > > > > > > How can I repair my tree? > > > > > > > > > > > > I have a message board system in which the messages are grouped by > > > "message_board_id", thus my model is: > > > > > > acts_as_nested_set :scope => :message_board_id > > > > > > > > > > > > Somehow the tree is messed up, inasmuch as some roots (parent_id > == > > > null) are being set to the children of some other message, so I cannot > > > successfully repair it. I'm not sure if I'm performing incorrect > operations > > > or what, but somehow I need to repair my tree where message_board_id = > 34 > > > (or whatever it is). > > > > > > > > > > > > It seems as if renumber_full_tree tries to find the virtual root > for a > > > given node, but since the root itself is a CHILD of another node, the > whole > > > thing fails. My layman's guess is that the "root" condition is wrong, > since > > > it's doing WHERE parent_id IS NULL ... AND lft BETWEEN .. AND .. > > > > > > > > > > > > Well, if the root is incorrectly between something, then the lft > would > > > fail, no? Maybe I'm misreading that. Help!! > > > > > > > > > > > > Thanks, > > > > > > > > > > > > -- > > > > > > Matt > > > > > > > > > > > > > > > > > > On 8/14/07, Matt Rogish wrote: > > > > > > > Under heavy load we are getting significantly screwed up data. I > > > have to run renumber_full_tree in script/console production order to > repair > > > the thing. > > > > > > > > > > > > > > Obviously this is a bad thing, but I don't even know where to > start > > > to fix it. Any ideas? > > > > > > > > > > > > > > Thanks, > > > > > > > > > > > > > > -- > > > > > > > Matt > > > > > > > > > > > > > > > > > > > ________________________________ > > > > > > > > > _______________________________________________ > > > > > > Betternestedset-talk mailing list > > > > > > Betternestedset-talk at rubyforge.org > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > http://rubyforge.org/mailman/listinfo/betternestedset-talk > > > > > > > > > > > > > > > > > > _______________________________________________ > > > > > > Betternestedset-talk mailing list > > > > > > Betternestedset-talk at rubyforge.org > > > > > > > > > > http://rubyforge.org/mailman/listinfo/betternestedset-talk > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > _______________________________________________ > > > Betternestedset-talk mailing list > > > Betternestedset-talk at rubyforge.org > > > > http://rubyforge.org/mailman/listinfo/betternestedset-talk > > > > > > > > _______________________________________________ > > Betternestedset-talk mailing list > > Betternestedset-talk at rubyforge.org > > > http://rubyforge.org/mailman/listinfo/betternestedset-talk > > > > > _______________________________________________ > Betternestedset-talk mailing list > Betternestedset-talk at rubyforge.org > http://rubyforge.org/mailman/listinfo/betternestedset-talk > > From hunterp at gmail.com Wed Aug 15 01:58:24 2007 From: hunterp at gmail.com (Hunter Peress) Date: Tue, 14 Aug 2007 23:58:24 -0600 Subject: [Betternestedset-talk] Why so many select * when adding child? Message-ID: <3585b2e10708142258l229523aaj8798abdf281d2362@mail.gmail.com> Hi, all i am doing is adding a new child: new = Menu.new new.save new.move_to_child_of Menu.find(params[:menu][:id] Yet, there are so many select * ... why? SQL (0.001530 ) BEGIN SQL (0.002496) SELECT max(rgt) AS max_rgt FROM menus WHERE (1 = 1) Menu Create (0.044471) INSERT INTO menus ("updated_at", "lft", "lock_version", "parent_id", "rgt", "created_at") VALUES('2007-08-14 2 3:28:23.611885', 9, 0, NULL, 10, '2007-08-14 23:28:23.611885') SQL (0.048153) SELECT currval('menus_id_seq') SQL (0.032054) COMMIT Menu Load (0.026600) SELECT * FROM menus WHERE (menus."id" = 3) SQL (0.001428) BEGIN Menu Load (0.048451) SELECT * FROM menus WHERE (menus."id" = 5) Menu Load (0.132441) SELECT * FROM menus WHERE (menus."id" = 3) Menu Update (0.026690) UPDATE menus SET lft = CASE WHEN lft BETWEEN 8 AND 8 THEN lft + 2 WHEN lft BETWEEN 9 AND 10 THEN lft + -1 ELSE lft END, rgt = CASE WHEN rgt BETWEEN 8 AND 8 THEN rgt + 2 WHEN rgt BETWEEN 9 AND 10 THEN rgt + -1 ELSE rgt END, parent_id = CASE WHEN id = 5 THEN 3 ELSE parent_id END WHERE (1 = 1) Menu Load (0.002911) SELECT * FROM menus WHERE (menus."id" = 5) Menu Load (0.001854) SELECT * FROM menus WHERE (menus."id" = 3) SQL (0.006460) COMMIT -------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/betternestedset-talk/attachments/20070814/6f39e055/attachment.html From tekin at raid.nu Wed Aug 15 06:52:09 2007 From: tekin at raid.nu (Tekin Suleyman) Date: Wed, 15 Aug 2007 11:52:09 +0100 Subject: [Betternestedset-talk] Concurrency issues? In-Reply-To: <46C20C92.9070601@goldnoteexpress.com> Message-ID: <00ad01c7df2a$541bff90$0500000a@rude10> Now you've got me worried! I'm currently using tags/stable and although I've had no problems with it, looking through the repository it looks like trunk has moved on significantly. Is trunk fully backwards compatible? -----Original Message----- From: betternestedset-talk-bounces at rubyforge.org [mailto:betternestedset-talk-bounces at rubyforge.org] On Behalf Of Jeremy Nicoll Sent: 14 August 2007 21:12 To: betternestedset-talk at rubyforge.org Subject: Re: [Betternestedset-talk] Concurrency issues? Thanks Matt - I'm glad you found this before my app went to production :). Good luck with yours. -- Jeremy Nicoll Krishna Dole wrote: Hey Matt, You were right-- there was a bug in the renumbering when working with virtual roots. I have fixed it in trunk. You can get the fixed version with script/plugin install svn://rubyforge.org/var/svn/betternestedset/trunk Thanks for reporting this. Krishna On 8/14/07, Matt Rogish wrote: My guess is that there's a bug in the implementation of renumber_full_tree/calc_numbers which is causing this problem. The dataset with overlapping numbers is what resulted from applying renumber_full_tree; thus something is not quite right with that method... I have a copy of SQL for Smarties (2nd ed), so I'll try and see if the two algorithms diverge at all and/or provide a patch if I can help it. :) Thanks, -- Matt On 8/14/07, Matt Rogish wrote: The problem is, as I see it, overlapping left and right columns. Shouldn't the lft/right be one apart, or am I wrong. For example: mysql> select id, parent_id, lft, rgt from messages where message_board_id = 1926 and parent_id is null order by lft; +--------+-----------+------+------+ | id | parent_id | lft | rgt | +--------+-----------+------+------+ | 9472 | NULL | 1 | 2 | | 9473 | NULL | 2 | 37 | | 9474 | NULL | 37 | 44 | | 9475 | NULL | 44 | 45 | | 9476 | NULL | 45 | 74 | | 9477 | NULL | 74 | 75 | | 9478 | NULL | 75 | 114 | | 9487 | NULL | 114 | 179 | | 9479 | NULL | 179 | 348 | | 9488 | NULL | 478 | 515 | | 9482 | NULL | 515 | 520 | | 9483 | NULL | 520 | 525 | | 9484 | NULL | 525 | 526 | | 9485 | NULL | 526 | 579 | | 334881 | NULL | 579 | 580 | | 335201 | NULL | 581 | 584 | | 335234 | NULL | 585 | 586 | +--------+-----------+------+------+ So the only ones "correct" are id = 335201 and id = 335234? I attached the entire dataset. What is happening is that the BETWEEN statement that better nested set is executing looks something like this: m = Message.find( 9478 ) m.all_children.each{ stuff } SQL is: SELECT * FROM messages WHERE (message_board_id = 1926 AND (lft BETWEEN 75 AND 114)) ORDER BY lf Since BETWEEN is inclusive, that result pulls all the children correctly but incorrectly pulls out the next root, message id = 9487. I'm not sure if that means renumber_entire_tree needs to be fixed, or the actual move_to_child does, but something isn't right. -- Matt On 8/14/07, Matt Rogish wrote: I'm not writing any SQL, I'm using built-in better-nested-set functions. Here's my save: def create @message = Message.new(params[:message]) if @message.save flash[:notice] = 'Message was successfully created.' if params[:message][:parent_id] @message.move_to_child_of( Message.find params[:message][:parent_id] ) @message.save end end end -- Matt On 8/14/07, Jeremy Nicoll wrote: I think it would be best if you could post your SQL that is messed up as well as the code you are using to save your nodes. Unfortunately we can't tell you what is wrong until we actually see the logic behind what you are doing. -- Jeremy Nicoll Matt Rogish wrote: How can I repair my tree? I have a message board system in which the messages are grouped by "message_board_id", thus my model is: acts_as_nested_set :scope => :message_board_id Somehow the tree is messed up, inasmuch as some roots (parent_id == null) are being set to the children of some other message, so I cannot successfully repair it. I'm not sure if I'm performing incorrect operations or what, but somehow I need to repair my tree where message_board_id = 34 (or whatever it is). It seems as if renumber_full_tree tries to find the virtual root for a given node, but since the root itself is a CHILD of another node, the whole thing fails. My layman's guess is that the "root" condition is wrong, since it's doing WHERE parent_id IS NULL ... AND lft BETWEEN .. AND .. Well, if the root is incorrectly between something, then the lft would fail, no? Maybe I'm misreading that. Help!! Thanks, -- Matt On 8/14/07, Matt Rogish wrote: Under heavy load we are getting significantly screwed up data. I have to run renumber_full_tree in script/console production order to repair the thing. Obviously this is a bad thing, but I don't even know where to start to fix it. Any ideas? Thanks, -- Matt ________________________________ _______________________________________________ Betternestedset-talk mailing list Betternestedset-talk at rubyforge.org http://rubyforge.org/mailman/listinfo/betternestedset-talk _______________________________________________ Betternestedset-talk mailing list Betternestedset-talk at rubyforge.org http://rubyforge.org/mailman/listinfo/betternestedset-talk _______________________________________________ Betternestedset-talk mailing list Betternestedset-talk at rubyforge.org http://rubyforge.org/mailman/listinfo/betternestedset-talk _______________________________________________ Betternestedset-talk mailing list Betternestedset-talk at rubyforge.org http://rubyforge.org/mailman/listinfo/betternestedset-talk -------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/betternestedset-talk/attachments/20070815/7898a630/attachment-0001.html From dontfall at gmail.com Wed Aug 15 12:02:27 2007 From: dontfall at gmail.com (Krishna Dole) Date: Wed, 15 Aug 2007 12:02:27 -0400 Subject: [Betternestedset-talk] Why so many select * when adding child? In-Reply-To: <3585b2e10708142258l229523aaj8798abdf281d2362@mail.gmail.com> References: <3585b2e10708142258l229523aaj8798abdf281d2362@mail.gmail.com> Message-ID: <8d64b97d0708150902i40aebd74oc98ddf0202037f94@mail.gmail.com> Hi Hunter, Starting from the second 'BEGIN', both the child and parent must be reloaded from the database to ensure that we are concurrency-safe (the lft/rgt values could have been altered by adds/moves/deletes of other objects). After the database is updated, they must be reloaded again, because the update happens only in the db, not the objects. Does that make sense? It is true that selecting '*' is unnecessary-- I'm looking at passing :select => "#{left_col_name}, #{right_col_name}, #{parent_col_name}" to #reload, which should give a performance boost to models with lots of columns/data. Krishna On 8/15/07, Hunter Peress wrote: > Hi, all i am doing is adding a new child: > > new = Menu.new > new.save > new.move_to_child_of Menu.find(params[:menu][:id] > > Yet, there are so many select * ... why? > > SQL (0.001530 ) BEGIN > SQL (0.002496) SELECT max(rgt) AS max_rgt FROM menus WHERE (1 = 1) > Menu Create (0.044471) INSERT INTO menus ("updated_at", "lft", > "lock_version", "parent_id", "rgt", "created_at") VALUES('2007-08-14 2 > 3:28:23.611885', 9, 0, NULL, 10, '2007-08-14 23:28:23.611885') > SQL (0.048153) SELECT currval('menus_id_seq') > SQL (0.032054) COMMIT > Menu Load (0.026600) SELECT * FROM menus WHERE (menus."id" = 3) > SQL (0.001428) BEGIN > Menu Load (0.048451) SELECT * FROM menus WHERE (menus."id" = 5) > Menu Load (0.132441) SELECT * FROM menus WHERE (menus."id" = 3) > Menu Update (0.026690) UPDATE menus SET lft = CASE WHEN lft BETWEEN 8 > AND 8 THEN lft + 2 WHEN lft BETWEEN 9 AND 10 THEN lft + -1 ELSE > lft END, rgt = CASE WHEN rgt BETWEEN 8 AND 8 THEN rgt + 2 WHEN rgt BETWEEN > 9 AND 10 THEN rgt + -1 ELSE rgt END, parent_id = CASE WHEN id > = 5 THEN 3 ELSE parent_id END WHERE (1 = 1) > Menu Load (0.002911) SELECT * FROM menus WHERE (menus."id" = 5) > Menu Load (0.001854) SELECT * FROM menus WHERE (menus."id" = 3) > SQL (0.006460) COMMIT > > _______________________________________________ > Betternestedset-talk mailing list > Betternestedset-talk at rubyforge.org > http://rubyforge.org/mailman/listinfo/betternestedset-talk > > From dontfall at gmail.com Wed Aug 15 13:57:29 2007 From: dontfall at gmail.com (Krishna Dole) Date: Wed, 15 Aug 2007 13:57:29 -0400 Subject: [Betternestedset-talk] New release? (was: Concurrency issues?) Message-ID: <8d64b97d0708151057g12d84d6dnb6979461cf515464@mail.gmail.com> I believe trunk is currently backwards compatible with stable. Since the renumber_full_tree bug is serious for those using virtual roots, I'd like to tag a new release. Any thoughts/objections? Krishna On 8/15/07, Tekin Suleyman wrote: > > > Now you've got me worried! > > I'm currently using tags/stable and although I've had no problems with it, > looking through the repository it looks like trunk has moved on > significantly. Is trunk fully backwards compatible? > > > > -----Original Message----- > From: betternestedset-talk-bounces at rubyforge.org > [mailto:betternestedset-talk-bounces at rubyforge.org] On > Behalf Of Jeremy Nicoll > Sent: 14 August 2007 21:12 > To: betternestedset-talk at rubyforge.org > Subject: Re: [Betternestedset-talk] Concurrency issues? > > Thanks Matt - I'm glad you found this before my app went to production > :). Good luck with yours. > > -- > Jeremy Nicoll > > Krishna Dole wrote: > Hey Matt, > > You were right-- there was a bug in the renumbering when working with > virtual roots. I have fixed it in trunk. You can get the fixed version > with > > script/plugin install > svn://rubyforge.org/var/svn/betternestedset/trunk > > Thanks for reporting this. > > Krishna > > On 8/14/07, Matt Rogish wrote: > > > My guess is that there's a bug in the implementation of > renumber_full_tree/calc_numbers which is causing this problem. The dataset > with overlapping numbers is what resulted from applying renumber_full_tree; > thus something is not quite right with that method... > > I have a copy of SQL for Smarties (2nd ed), so I'll try and see if the two > algorithms diverge at all and/or provide a patch if I can help it. :) > > Thanks, > > -- > Matt > > > On 8/14/07, Matt Rogish wrote: > > > The problem is, as I see it, overlapping left and right columns. Shouldn't > > the lft/right be one apart, or am I wrong. > > > For example: > mysql> select id, parent_id, lft, rgt from messages where message_board_id > > = 1926 and parent_id is null order by lft; > > > +--------+-----------+------+------+ > | id | parent_id | lft | rgt | > +--------+-----------+------+------+ > | 9472 | NULL | 1 | 2 | > | 9473 | NULL | 2 | 37 | > | 9474 | NULL | 37 | 44 | > | 9475 | NULL | 44 | 45 | > | 9476 | NULL | 45 | 74 | > | 9477 | NULL | 74 | 75 | > | 9478 | NULL | 75 | 114 | > | 9487 | NULL | 114 | 179 | > | 9479 | NULL | 179 | 348 | > | 9488 | NULL | 478 | 515 | > | 9482 | NULL | 515 | 520 | > | 9483 | NULL | 520 | 525 | > | 9484 | NULL | 525 | 526 | > | 9485 | NULL | 526 | 579 | > | 334881 | NULL | 579 | 580 | > | 335201 | NULL | 581 | 584 | > | 335234 | NULL | 585 | 586 | > +--------+-----------+------+------+ > > So the only ones "correct" are id = 335201 and id = 335234? > > I attached the entire dataset. What is happening is that the BETWEEN > > statement that better nested set is executing looks something like this: > > > m = Message.find( 9478 ) > m.all_children.each{ stuff } > > SQL is: > SELECT * FROM messages WHERE (message_board_id = 1926 AND (lft BETWEEN 75 > > AND 114)) ORDER BY lf > > > Since BETWEEN is inclusive, that result pulls all the children correctly > > but incorrectly pulls out the next root, message id = 9487. > > > I'm not sure if that means renumber_entire_tree needs to be fixed, or the > > actual move_to_child does, but something isn't right. > > > -- > > Matt > > > On 8/14/07, Matt Rogish wrote: > > > I'm not writing any SQL, I'm using built-in better-nested-set functions. > > Here's my save: > def create > @message = Message.new(params[:message]) > > if @message.save > flash[:notice] = 'Message was successfully created.' > > if params[:message][:parent_id] > @message.move_to_child_of( Message.find > > params[:message][:parent_id] ) > > > > @message.save > end > end > end > > -- > Matt > > > > On 8/14/07, Jeremy Nicoll wrote: > > > I think it would be best if you could post your SQL that is messed > > up as well as the code you are using to save your nodes. Unfortunately we > can't tell you what is wrong until we actually see the logic behind what you > are doing. > > > > > -- > Jeremy Nicoll > > Matt Rogish wrote: > > How can I repair my tree? > > I have a message board system in which the messages are grouped by > > "message_board_id", thus my model is: > > > > > acts_as_nested_set :scope => :message_board_id > > Somehow the tree is messed up, inasmuch as some roots (parent_id == > > null) are being set to the children of some other message, so I cannot > successfully repair it. I'm not sure if I'm performing incorrect operations > or what, but somehow I need to repair my tree where message_board_id = 34 > (or whatever it is). > > > > > It seems as if renumber_full_tree tries to find the virtual root for a > > given node, but since the root itself is a CHILD of another node, the whole > thing fails. My layman's guess is that the "root" condition is wrong, since > it's doing WHERE parent_id IS NULL ... AND lft BETWEEN .. AND .. > > > > > Well, if the root is incorrectly between something, then the lft would > > fail, no? Maybe I'm misreading that. Help!! > > > > > Thanks, > > -- > Matt > > > On 8/14/07, Matt Rogish wrote: > > > Under heavy load we are getting significantly screwed up data. I > > have to run renumber_full_tree in script/console production order to repair > the thing. > > > > > > Obviously this is a bad thing, but I don't even know where to start > > to fix it. Any ideas? > > > > > > Thanks, > > -- > Matt > > > ________________________________ > > > > > _______________________________________________ > Betternestedset-talk mailing list > Betternestedset-talk at rubyforge.org > > > > > > > http://rubyforge.org/mailman/listinfo/betternestedset-talk > > > > > _______________________________________________ > Betternestedset-talk mailing list > Betternestedset-talk at rubyforge.org > > > http://rubyforge.org/mailman/listinfo/betternestedset-talk > > > > > > > > _______________________________________________ > Betternestedset-talk mailing list > Betternestedset-talk at rubyforge.org > http://rubyforge.org/mailman/listinfo/betternestedset-talk > > > > _______________________________________________ > Betternestedset-talk mailing list > Betternestedset-talk at rubyforge.org > http://rubyforge.org/mailman/listinfo/betternestedset-talk > > > > _______________________________________________ > Betternestedset-talk mailing list > Betternestedset-talk at rubyforge.org > http://rubyforge.org/mailman/listinfo/betternestedset-talk