Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

find and fix corrupted children counts #584

Open
acolchagoff opened this issue Jun 27, 2022 · 5 comments · May be fixed by #618
Open

find and fix corrupted children counts #584

acolchagoff opened this issue Jun 27, 2022 · 5 comments · May be fixed by #618

Comments

@acolchagoff
Copy link

We have a rather large database, and one of our clients wrote in about a bug that we determined to be a result of children_count being wrong for many many users ( we aren't really sure how many) Is there something I can do to regenerate all children counts in our database?

@ptorrsmith
Copy link

Something like this ? We didn't implement it as not yet had the need, so can't guarantee it's solid. (inspired by Ancestry::ClassMethods.rebuild_depth_cache!)

    # Rebuild children cache if it got corrupted or if counter caching was just turned on
    def rebuild_children_count!
      raise Ancestry::AncestryException.new(I18n.t("ancestry.cannot_rebuild_children_count")) unless respond_to? :counter_cache_column
  
      self.ancestry_base_class.transaction do
        unscoped_where do |scope|
          scope.find_each do |node|
            node.update_attribute counter_cache_column, node.children.count
          end
        end
      end
    end

@kbrock
Copy link
Collaborator

kbrock commented Aug 9, 2022

The best way to do this is probably via a single sql query

This is probably not valid sql, but will hopefully get you close:

Direct descendents:

UPDATE #{table_name}
SET child_count = (
  select count(*)
  from table_name children
  where children.ancestry =
    case when #{table_name}.ancestry is null then #{table_name}.id::varchar
    else #{table_name}.ancestry || '/' || #{table_name}.id::varchar
    end
)

Probably wouldn't be that hard to get into a method.
String concatenation is mostly consistent across databases, mysql or sqlite may use + instead.

For all child decedents, we'd need to include both the ancestry || '/' || id and ancestry || '/' || id || '/%'

@kbrock kbrock linked a pull request Mar 4, 2023 that will close this issue
@kbrock
Copy link
Collaborator

kbrock commented Mar 15, 2023

@denodster I'm digging into what may be causing this.

So that I may mimic your environment as closely as possible:

  • What database are you using?
  • Have you overridden any callbacks like the destroy or update_descendants?
  • are you using update_strategy = :sql (I'm worried this may be the culprit)
  • are your trees very deep or relatively shallow?

Any anything else you can think of that may help reproduce would be great.

I'll also be adding:

  • adding rebuild_counter_cache! and rebuild_counter_cache_sql!
  • adding rebuild_depth_cache_sql!

@ptorrsmith If you could share similar information, that would be great, too. (so I can take that into account when looking into better support for dependant_count_cache.)

@kbrock
Copy link
Collaborator

kbrock commented Mar 25, 2023

@denodster would you possibly be running mysql?
I noticed locally that the touch tests seem to behaving differently on mysql than postgres. Wonder if the counters have a similar problem

@kbrock
Copy link
Collaborator

kbrock commented Apr 10, 2023

please check out rebuild_depth_cache! and rebuild_counter_cache! / rebuild_counter_cache_sql!

ref: #654 and #663

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants