Massive file creation slowing server

My server keeps slowing down due to having over 400,000 files - though I only have around 300 pages on the site (https://www.invitationtotuscany.com).

I’m looking into it but curious if anybody has any ideas as to what might be happening.

Grav is 1.17, the theme is based on Typhoon. Any suggestions as to what to check?

Screenshot 2021-09-28 at 10.23.27

@dan-james, Any idea in which folder these files are being created?

I’m trying to find out now - but no luck yet. I’m downloading everything from the server so I can root through it without breaking anything, and while I wait I’m going through options in my mind and checking on the file-manage in control panel. I don’t have SSH access so it’s a little slow. And the inode checker times out…

My local dev version of the site is 1.2GB, the one on the server is 7.5 - so something is awry…

@dan-james, May I presume you’ve already checked Grav’s folders to which data may be added over time, like: /backup, /cache, /images, /logs, /tmp

Yes, nothing seems excessive. The images are where I’d expect the auto-generated versions to be. I have around 75 properties each with roughly 20 images - so 1500 image files. /backup has one file in it, /cache obviously a lot more - but nowhere near 400,000.

It feels like there’s a script over-producing something - I added 5 pages yesterday and there are now around 30,000 more files somewhere…!!

@dan-james, And there is no increase when you don’t add pages?

@anon76427325 There might be something going on in the /cache/twig folder - it’s the last modified and there are a lot of folders in there.

One of the last modified is this one, which I think ran when I deleted one of the old backups - but why is it caching so many twig files?

<?php

use Twig\Environment;
use Twig\Error\LoaderError;
use Twig\Error\RuntimeError;
use Twig\Markup;
use Twig\Sandbox\SecurityError;
use Twig\Sandbox\SecurityNotAllowedTagError;
use Twig\Sandbox\SecurityNotAllowedFilterError;
use Twig\Sandbox\SecurityNotAllowedFunctionError;
use Twig\Source;
use Twig\Template;

/* partials/tools-backups.html.twig */
class __TwigTemplate_f59e30a0fbc178df1e5151ba15891f42a0515ec5f47ae10428242bfcfef0a593 extends \Twig\Template
{
    public function __construct(Environment $env)
    {
        parent::__construct($env);

        $this->parent = false;

        $this->blocks = [
        ];
    }

    protected function doDisplay(array $context, array $blocks = [])
    {
        // line 1
        echo "<div class=\"backups-content\">

    ";
        // line 3
        $context["data"] = $this->getAttribute(($context["admin"] ?? null), "data", [0 => "config/backups"], "method");
        // line 4
        echo "    ";
        $context["backups"] = $this->getAttribute($this->getAttribute(($context["grav"] ?? null), "backups", []), "getAvailableBackups", [], "method");
        // line 5
        echo "    ";
        $context["profiles"] = $this->getAttribute($this->getAttribute(($context["grav"] ?? null), "backups", []), "getBackupProfiles", [], "method");
        // line 6
        echo "    ";
        $context["purge_config"] = $this->getAttribute($this->getAttribute(($context["grav"] ?? null), "backups", []), "getPurgeConfig", [], "method");
        // line 7
        echo "    ";
        $context["newest_date"] = $this->getAttribute(twig_first($this->env, ($context["backups"] ?? null)), "date", []);
        // line 8
        echo "    ";
        $context["newest_backup"] = ((($context["newest_date"] ?? null)) ? ($this->env->getExtension('Grav\Common\Twig\Extension\GravExtension')->nicetimeFunc(($context["newest_date"] ?? null), false, false)) : ("none"));
        // line 9
        echo "    ";
        $context["oldest_date"] = $this->getAttribute(twig_last($this->env, ($context["backups"] ?? null)), "date", []);
        // line 10
        echo "    ";
        $context["oldest_backup"] = ((($context["oldest_date"] ?? null)) ? ($this->env->getExtension('Grav\Common\Twig\Extension\GravExtension')->nicetimeFunc(($context["oldest_date"] ?? null), false, false)) : ("none"));
        // line 11
        echo "
    ";
        // line 12
        switch ($this->getAttribute(($context["purge_config"] ?? null), "trigger", [])) {
            case "number":
            {
                // line 14
                echo "        ";
                $context["count"] = count(($context["backups"] ?? null));
                // line 15
                echo "        ";
                $context["max_backups"] = $this->getAttribute(($context["purge_config"] ?? null), "max_backups_count", []);
                // line 16
                echo "        ";
                if ((($context["max_backups"] ?? null) > 0)) {
                    // line 17
                    echo "            ";
                    $context["percent_used"] = (((($context["count"] ?? null) == 0)) ? (0) : ((100 - ((($context["count"] ?? null) / ($context["max_backups"] ?? null)) * 100))));
                    // line 18
                    echo "        ";
                } else {
                    // line 19
                    echo "            ";
                    $context["percent_used"] = 100;
                    // line 20
                    echo "        ";
                }
                // line 21
                echo "        ";
                $context["bar_msg"] = $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.BACKUPS_PURGE_NUMBER", [0 => ($context["count"] ?? null), 1 => $this->getAttribute(($context["purge_config"] ?? null), "max_backups_count", [])]);
                // line 22
                echo "    ";
                break;
            }
            case "time":
            {
                // line 23
                echo "        ";
                $context["last"] = twig_last($this->env, ($context["backups"] ?? null));
                // line 24
                echo "        ";
                $context["days"] = (((($context["last"] ?? null) == null)) ? (0) : ($this->getAttribute($this->getAttribute(twig_date_converter($this->env, "now"), "diff", [0 => $this->getAttribute(($context["last"] ?? null), "time", [])], "method"), "days", [])));
                // line 25
                echo "        ";
                $context["percent_used"] = (((($context["days"] ?? null) == 0)) ? (0) : ((100 - ((($context["days"] ?? null) / $this->getAttribute(($context["purge_config"] ?? null), "max_backups_time", [])) * 100))));
                // line 26
                echo "        ";
                $context["bar_msg"] = $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.BACKUPS_PURGE_TIME", [0 => ($this->getAttribute(($context["purge_config"] ?? null), "max_backups_time", []) - ($context["days"] ?? null))]);
                // line 27
                echo "    ";
                break;
            }
            default:
            {
                // line 28
                echo "        ";
                $context["space_used"] = $this->getAttribute($this->getAttribute(($context["grav"] ?? null), "backups", []), "getTotalBackupsSize", [], "method");
                // line 29
                echo "        ";
                $context["space_available"] = ((($this->getAttribute(($context["purge_config"] ?? null), "max_backups_space", []) * 1024) * 1024) * 1024);
                // line 30
                echo "        ";
                $context["percent_used"] = (((($context["space_used"] ?? null) == 0)) ? (0) : ((100 - ((($context["space_used"] ?? null) / ($context["space_available"] ?? null)) * 100))));
                // line 31
                echo "        ";
                $context["bar_msg"] = $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.BACKUPS_PURGE_SPACE", [0 => $this->env->getExtension('Grav\Common\Twig\Extension\GravExtension')->niceFilesizeFunc(($context["space_used"] ?? null)), 1 => $this->env->getExtension('Grav\Common\Twig\Extension\GravExtension')->niceFilesizeFunc(($context["space_available"] ?? null))]);
                // line 32
                echo "    ";
            }
        }
        // line 33
        echo "
    <div id=\"admin-dashboard\">
      <div id=\"backups-stats\" class=\"dashboard-item\">
        <div class=\"primary-accent default-box-shadow\">
          <h1>";
        // line 37
        echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.BACKUPS_STATS"), "html", null, true);
        echo "</h1>
          <div class=\"admin-statistics-chart\">
            <div class=\"stats-info\">

                <div id=\"backups-usage\">
                    <div class=\"backups-usage-wrapper\">
                        ";
        // line 43
        if ((($context["percent_used"] ?? null) >= 100)) {
            // line 44
            echo "                            <div class=\"usage full\"></div>
                        ";
        } else {
            // line 46
            echo "                            <div class=\"usage\" style=\"width:";
            echo twig_escape_filter($this->env, ($context["percent_used"] ?? null), "html", null, true);
            echo "%\"></div>
                        ";
        }
        // line 48
        echo "                    </div>
                    <h1>";
        // line 49
        echo twig_escape_filter($this->env, ($context["bar_msg"] ?? null), "html", null, true);
        echo "</h1>
                </div>
            </div>

            <div class=\"flush-bottom button-bar stats-bar\">
              <span class=\"stat\">
                  <b>";
        // line 55
        echo twig_escape_filter($this->env, twig_length_filter($this->env, ($context["backups"] ?? null)), "html", null, true);
        echo "</b>
                  <i>";
        // line 56
        echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.BACKUPS_COUNT"), "html", null, true);
        echo "</i>
              </span>
              <span class=\"stat\">
                  <b>";
        // line 59
        echo twig_escape_filter($this->env, count(($context["profiles"] ?? null)), "html", null, true);
        echo "</b>
                  <i>";
        // line 60
        echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.BACKUPS_PROFILES_COUNT"), "html", null, true);
        echo "</i>
              </span>
                <span class=\"stat\">
                  <b>";
        // line 63
        echo twig_escape_filter($this->env, ($context["newest_backup"] ?? null), "html", null, true);
        echo "</b>
                  <i>";
        // line 64
        echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.BACKUPS_NEWEST"), "html", null, true);
        echo "</i>
              </span>
                <span class=\"stat\">
                  <b>";
        // line 67
        echo twig_escape_filter($this->env, ($context["oldest_backup"] ?? null), "html", null, true);
        echo "</b>
                  <i>";
        // line 68
        echo twig_escape_filter($this->env, $this->env->getExtension('Grav\Plugin\Admin\Twig\AdminTwigExtension')->tuFilter("PLUGIN_ADMIN.BACKUPS_OLDEST"), "html", null, true);
        echo "</i>
              </span>
            </div>
          </div>
        </div>
      </div>
    </div>

    ";
        // line 76
        $this->loadTemplate("partials/blueprints.html.twig", "partials/tools-backups.html.twig", 76)->display(twig_array_merge($context, ["blueprints" => $this->getAttribute(($context["data"] ?? null), "blueprints", []), "data" => ($context["data"] ?? null)]));
        // line 77
        echo "
    ";
        // line 78
        $this->loadTemplate("partials/modal-changes-detected.html.twig", "partials/tools-backups.html.twig", 78)->display($context);
        // line 79
        echo "

</div>
";
    }

    public function getTemplateName()
    {
        return "partials/tools-backups.html.twig";
    }

    public function isTraitable()
    {
        return false;
    }

    public function getDebugInfo()
    {
        return array (  219 => 79,  217 => 78,  214 => 77,  212 => 76,  201 => 68,  197 => 67,  191 => 64,  187 => 63,  181 => 60,  177 => 59,  171 => 56,  167 => 55,  158 => 49,  155 => 48,  149 => 46,  145 => 44,  143 => 43,  134 => 37,  128 => 33,  124 => 32,  121 => 31,  118 => 30,  115 => 29,  112 => 28,  106 => 27,  103 => 26,  100 => 25,  97 => 24,  94 => 23,  88 => 22,  85 => 21,  82 => 20,  79 => 19,  76 => 18,  73 => 17,  70 => 16,  67 => 15,  64 => 14,  60 => 12,  57 => 11,  54 => 10,  51 => 9,  48 => 8,  45 => 7,  42 => 6,  39 => 5,  36 => 4,  34 => 3,  30 => 1,);
    }

    /** @deprecated since 1.27 (to be removed in 2.0). Use getSourceContext() instead */
    public function getSource()
    {
        @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', E_USER_DEPRECATED);

        return $this->getSourceContext()->getCode();
    }

    public function getSourceContext()
    {
        return new Source("<div class=\"backups-content\">

    {% set data = admin.data('config/backups') %}
    {% set backups = grav.backups.getAvailableBackups() %}
    {% set profiles = grav.backups.getBackupProfiles() %}
    {% set purge_config = grav.backups.getPurgeConfig() %}
    {% set newest_date = (backups|first).date %}
    {% set newest_backup = newest_date ? newest_date|nicetime(false, false) : 'none' %}
    {% set oldest_date = (backups|last).date %}
    {% set oldest_backup = oldest_date ? oldest_date|nicetime(false, false) : 'none' %}

    {% switch purge_config.trigger %}
    {% case 'number' %}
        {% set count = backups|count %}
        {% set max_backups = purge_config.max_backups_count %}
        {% if max_backups > 0 %}
            {% set percent_used = count == 0 ? 0 : 100 - (count / max_backups * 100) %}
        {% else %}
            {% set percent_used = 100 %}
        {% endif %}
        {% set bar_msg = \"PLUGIN_ADMIN.BACKUPS_PURGE_NUMBER\"|tu([count, purge_config.max_backups_count]) %}
    {% case 'time' %}
        {% set last = backups|last %}
        {% set days = last == null ? 0 : (date('now')).diff(last.time).days %}
        {% set percent_used = days == 0 ? 0 : 100 - (days / purge_config.max_backups_time * 100) %}
        {% set bar_msg = \"PLUGIN_ADMIN.BACKUPS_PURGE_TIME\"|tu([(purge_config.max_backups_time - days)]) %}
    {% default %}
        {% set space_used = grav.backups.getTotalBackupsSize() %}
        {% set space_available = purge_config.max_backups_space * 1024 * 1024 * 1024 %}
        {% set percent_used = space_used == 0 ? 0 : 100 - (space_used / space_available * 100) %}
        {% set bar_msg = \"PLUGIN_ADMIN.BACKUPS_PURGE_SPACE\"|tu([space_used|nicefilesize, space_available|nicefilesize]) %}
    {% endswitch %}

    <div id=\"admin-dashboard\">
      <div id=\"backups-stats\" class=\"dashboard-item\">
        <div class=\"primary-accent default-box-shadow\">
          <h1>{{ \"PLUGIN_ADMIN.BACKUPS_STATS\"|tu }}</h1>
          <div class=\"admin-statistics-chart\">
            <div class=\"stats-info\">

                <div id=\"backups-usage\">
                    <div class=\"backups-usage-wrapper\">
                        {% if percent_used >= 100 %}
                            <div class=\"usage full\"></div>
                        {% else %}
                            <div class=\"usage\" style=\"width:{{ percent_used }}%\"></div>
                        {% endif %}
                    </div>
                    <h1>{{ bar_msg }}</h1>
                </div>
            </div>

            <div class=\"flush-bottom button-bar stats-bar\">
              <span class=\"stat\">
                  <b>{{ backups|length }}</b>
                  <i>{{ \"PLUGIN_ADMIN.BACKUPS_COUNT\"|tu }}</i>
              </span>
              <span class=\"stat\">
                  <b>{{ profiles|count }}</b>
                  <i>{{ \"PLUGIN_ADMIN.BACKUPS_PROFILES_COUNT\"|tu }}</i>
              </span>
                <span class=\"stat\">
                  <b>{{ newest_backup }}</b>
                  <i>{{ \"PLUGIN_ADMIN.BACKUPS_NEWEST\"|tu }}</i>
              </span>
                <span class=\"stat\">
                  <b>{{ oldest_backup }}</b>
                  <i>{{ \"PLUGIN_ADMIN.BACKUPS_OLDEST\"|tu }}</i>
              </span>
            </div>
          </div>
        </div>
      </div>
    </div>

    {% include 'partials/blueprints.html.twig' with { blueprints: data.blueprints, data: data } %}

    {% include 'partials/modal-changes-detected.html.twig' %}


</div>
", "partials/tools-backups.html.twig", "/home/invitati/public_html/user/plugins/admin/themes/grav/templates/partials/tools-backups.html.twig");
    }
}

@dan-james, The Twig file seems to be referencing Admin. Are you using Admin?

Yes, I am. I use it for most things.

@anon76427325 Could i empty the cache folders and see if that helps?

@dan-james, Just trying to narrow size while blindfolded…

  • You mentioned an increase in number of files when adding pages.
    • Is there an increase without adding pages?
    • Is there an increase if you add pages using command line?
  • Are there any errors in the log files of Grav and Apache?
  • Does the Twig file mentioned above have many copies?
  • Do you see an increase of files after every use of the Tools/Backup section of Admin?

@dan-james, I guess the only penalty of clearing the cache is a performance hit at first access.

I’m in the process of downloading the whole site, just in case - then I’ll delete some cache files so I can get into admin (locked out due to server overload at the moment - just too many nodes, not real overload). Then I’ll run some tests as you suggest and narrow it down…

@anon76427325 It’s the /doctrine cache - I emptied it and now have 42,000 files instead of 420,000. Now I need to find out why the cache wasn’t purging - it was set to in system.yaml.

Thanks for your help!

@dan-james, You’re not the first hitting a growing /cache/doctrine. Cache directory growing infinitely

Unfortunately, it doesn’t provide a solution. A suggestion only.

1 Like

@anon76427325 I’ll post here if I find a solution. I’ll check the folder size in a while…

As original poster of that phenomenon I would like to add, that I have not found any solution for this problem. My weekly routine is currently to clear the cache manually, once the quota of the domain is sending warning e-mails.

I really do not understand, how this is happening. I assume that the cache clearing mechanism inside of Grav is only triggered once another page is visited. As my domain currently has only the start page and no further links, this might “virtually break” something.

It is quite annoying, especially when you are on vacation and find 1.000 warning mails afterwards, but I really want to find out, why this is happening, before I start adding further content to the site.

@Vince42, Is cache/doctrine also in your case the one that is growing to the max?

Hi @Vince42, I haven’t found a solution either, but I have found that the ‘purge old cache’ option on the admin page seems to do the trick:

Screenshot 2021-10-15 at 14.33.17