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

Reduce start up time by loading finished Code First models from a persistent cache #40

Closed
wants to merge 1 commit into from

Conversation

@j-Edge
Copy link
Contributor

j-Edge commented Aug 9, 2016

Ported from CodePlex Pull Request 8468
Fix for CodePlex Work Items #1876 and #2631
Reduce start up time by loading finished Code First models from a persistent cache
Incorporates DbModelStore persistent cache to reduce Code First Startup Time

With these changes, first AppDomain calls to context.Database.Initialize for a model with just over 600 models and a null initializer dropped from 12-14 seconds to about 1.9 seconds after the edmx was written, saving 10-12 seconds on initialization. The first call to write the edmx still ran in 12-14 seconds (no noticeable delay added).

Includes code from the patch by emilcicos attached to work item #1876, with modifications to fix known issues.

Code changed after applying the patch:

  • DefaultDbModelStore invalidates (deletes) the persistent store based on comparing context dll and edmx file last updated timestamps.
  • EdmxWriter was updated to read from the DbModelStore when available. This fixed a null reference when using DropCreateAlways initializer with a DbModelStore (compiledModel.CachedModelBuilder is null when the model is loaded from the store). Added function DbModelStore.TryGetEdmx to allow the EdmxWriter to read the edmx directly from storage.
  • LazyInternalContext.ModelMatches changes in the patch were removed as they were unnecessary after the EdmxWriter fix.
  • Added unit and functional test coverage for code changes including the patch code. DefaultDbModelStoreTests functional test covers the end-to-end functionality of using a DbModelStore.
Reduce start up time by loading finished Code First models from a persistent cache
Incorporates DbModelStore persistent cache
Work item: 1876, 2631
@dnfclas

This comment has been minimized.

Copy link

dnfclas commented Aug 9, 2016

Hi @j-Edge, I'm your friendly neighborhood .NET Foundation Pull Request Bot (You can call me DNFBOT). Thanks for your contribution!

In order for us to evaluate and accept your PR, we ask that you sign a contribution license agreement. It's all electronic and will take just minutes. I promise there's no faxing. https://cla2.dotnetfoundation.org.

TTYL, DNFBOT;

@dnfclas dnfclas added the cla-required label Aug 9, 2016
@dnfclas

This comment has been minimized.

Copy link

dnfclas commented Aug 9, 2016

@j-Edge, Thanks for signing the contribution license agreement so quickly! Actual humans will now validate the agreement and then evaluate the PR.

Thanks, DNFBOT;

@dnfclas dnfclas added cla-signed and removed cla-required labels Aug 9, 2016
@ilmax

This comment has been minimized.

Copy link
Contributor

ilmax commented Aug 9, 2016

🎉

@brandondahler

This comment has been minimized.

Copy link
Contributor

brandondahler commented Aug 13, 2016

Instead of saving to an xml file and relying on the last modified date and other metadata, I propose we should use a resource file that automatically invalidates itself depending on whether the dll has been recompiled or not.

Sample use case where last modified date would not be sufficient:

  1. Update entity assembly with new migration and deploy to production.
  2. Revert change made, manually run Down on migration against database and revert .exe/.dll to previously deployed version.

Depending on deployment methodologies, it is possible that the original modification time would be restored on the .exe/.dll . If the .entitycache was not manually deleted by revert process then our DbModelStore would load the incorrect edmx.

I wrote a basic proof of concept to allow us to read/write resources out to a XYZ.{exe,dll}.entitycache file and automatically invalidate when the executable is modified. No special assembly references are required.

using System;
using System.Collections;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Resources;

namespace Test
{
    public static class Program
    {
        public static void Main(string[] args)
        {
            var assembly = Assembly.GetExecutingAssembly();
            var currentModuleVersionId = assembly.ManifestModule.ModuleVersionId;
            Console.WriteLine(currentModuleVersionId);
            Console.WriteLine();


            var requiresRebuild = true;
            var resourcePath = assembly.Location + ".entitycache";

            if (File.Exists(resourcePath))
            {
                using (var resourceReader = new ResourceReader(resourcePath))
                {
                    var resourceDictionary = resourceReader.OfType<DictionaryEntry>()
                        .ToDictionary(de => de.Key, de => de.Value);


                    if (resourceDictionary.ContainsKey("_.Assembly.ModuleVersionId"))
                    {
                        var storedModuleVersionId = (Guid) resourceDictionary["_.Assembly.ModuleVersionId"];
                        requiresRebuild = (storedModuleVersionId != currentModuleVersionId);
                    }
                }
            }

            if (requiresRebuild)
            {
                Console.WriteLine("Rebuilding resource file.");
                using (var resourceWriter = new ResourceWriter(resourcePath))
                {
                    resourceWriter.AddResource(
                        "_.Assembly.ModuleVersionId",
                        currentModuleVersionId);
                }
            } else {
                Console.WriteLine("Rebuild not required.");
            }
        }
    }
}

If desired, I can provide a pull request to @j-Edge to implement this kind of cache invalidation.

@ThomasZitzler

This comment has been minimized.

Copy link

ThomasZitzler commented Aug 24, 2016

Please keep the option to save the model to an xml file. We have a more or less dynamically building system that loads entities from multiple dlls and builds the model based on the found entities.

There it's not possible to save it into a dll/exe as resource.

@rowanmiller rowanmiller modified the milestone: 6.2.0 Dec 5, 2016
@ajcvickers

This comment has been minimized.

Copy link
Member

ajcvickers commented Dec 12, 2016

This has now been merged. Thanks for the contribution!

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

Successfully merging this pull request may close these issues.

None yet

7 participants
You can’t perform that action at this time.