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

Faster element duplication #2066

Merged
merged 13 commits into from
Apr 13, 2021
Merged

Conversation

mamhoff
Copy link
Contributor

@mamhoff mamhoff commented Apr 12, 2021

What is this pull request for?

This speeds up element duplication by picking all child elements from the source element's page version's element repository, the creating the new elements, without touching related database records or updating element positions.

The speedup here is considerable: In a tiny benchmark, we managed to reduce publishing time by more than half:

Main branch:

  0.820700   0.006808   0.827508 (  0.832897)

This branch:

  0.357914   0.004525   0.362439 (  0.364606)

The benchmark is the following file, feel free to add it to your project and try yourself:

require "rails_helper"
require "benchmark"

RSpec.describe Alchemy::Page::Publisher do
  describe "#publish!" do
    let!(:pages) do
      (0..10).map do
        page = create(:alchemy_page, autogenerate_elements: true)
        create(:alchemy_element, page_version: page.draft_version, parent_element: page.draft_version.elements.first)
        page
      end
    end

    it "is not so slow" do
      result = Benchmark.measure do
        pages.each { |page| described_class.new(page).publish!(public_on: Time.current) }
      end
      puts result
    end
  end
end

This is co-authored by @tvdeyen - I just cleaned up the commit history and added some specs.

Checklist

  • I have followed Pull Request guidelines
  • I have added a detailed description into each commit message
  • I have added tests to cover this change

The Element Repository behaves a lot like an ActiveRecord::Relation, but
does everything in-memory rather than executing SQL. This will allow us
to increase performance when reading elements from a page version.
When copying, we copy a content to another element. We need to skip the
element ID in these cases.
This will help us render and copy nested elements!
When creating an element, we do not need to touch it for every time it
creates a content.
This change aligns the Hash we're merging into with the Hash we're
merging from.
This adds a service class that duplicates an element quickly. It can
accept an optional repository so that nested elements do not generate
new database calls.
It's faster, and we get to remove some code from the Element class.
This should speed up page publishing considerably. Specs are sufficient.
`tag_list` generates a query for each element, even if they're already
loaded.
This speeds up page publishing by a fair amount.
@mamhoff mamhoff force-pushed the faster-element-duplication branch 3 times, most recently from c76eafe to a3386fc Compare April 12, 2021 15:17
Copy link
Member

@tvdeyen tvdeyen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice. I think we can have accurate positions and the performance improvement.

app/models/alchemy/page/publisher.rb Outdated Show resolved Hide resolved
This saves a query per element!
These specs would previously fail as their element's updated at would
not, actually, be `3.hours.ago`, but `Time.current - $TESTRUNTIME`. This
is more explicit with setting the column, and fixes the specs.
This makes sure the element indexes start with 1, as `acts_as_list`
expects.

It also wraps the creation of nested elements in the `DuplicateElement`
class in an `Element.acts_as_list_no_update` block. The code in here is
safe, and when called from e.g. Alchemy::Element#copy, it makes it
faster, too.
Copy link
Member

@tvdeyen tvdeyen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice

@tvdeyen tvdeyen merged commit 972eb1f into AlchemyCMS:main Apr 13, 2021
@tvdeyen tvdeyen added this to the 6.0 milestone Apr 13, 2021
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 this pull request may close these issues.

2 participants