Uploaded image for project: 'Subversion'
  1. Subversion
  2. SVN-4796

SVN leaks exponentially significant amount of memory on commit

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Closed
    • Critical
    • Resolution: Not A Problem
    • 1.11.0, 1.10.2
    • None

    Description

      This is a clearly reproducible problem on SVN versions 1.10.2 and the latest 1.11.0.

      We found two similar issues SVN-1964, SVN-3411 closed already, but obviously beyond our case. So, these are just mentioned for reference.

      Description

      We're going to use the SVN API in order to create and then commit multiple transactions with multiple files. In order to simplify the scenario, within the code below, we will apply only 3 actions per transaction:

      1. Create a transaction
      2. Add only one directory or one empty file (file with content makes no difference)
      3. Commit the transaction

      Now let`s loop many transactions like this one in sequence (no concurrent usage).

      After each commit SVN consumes exponentially amount of memory which is never released afterwords, as follows (Number of transaction - Application's memory usage):

      0 - 380 kb (initial state when the application is started with 0 transactions)

      1`000 - 20 Mb

      2`000 - 66 Mb

      3`000 - 120 Mb

      4`000 - 210 Mb

      5`000 - 320 Mb

      6`000 - 455 Mb

      7`000 - 607 Mb

      8`000 - 808 Mb

      9`000 - 1.1 Gb

      10`000 - 1.4 Gb

      Observations

      Few curious facts observed during the tests:

      • If we delete the added file before committing, the transaction remains empty, then there is no memory leakage;
      • If we add not only one file or dir but 40`000 - 48`000 entities in one transaction then the files are being created VERY slowly, and the memory consumption is doubled or even tippled compared to the table above;
      • If we create and commit 10`000 entities (in our example) in the root directory (it is important to do that in the root), and we stop the application, then on the next application start with the same repository there are three cases:
        • if we add more entities in the root again, then the memory leakage is increased with the same proportions, as described above, BUT,
        • if we add more entities in subdirectory, then the memory allocation is stopped by 20 Mb until a threshold of about 9`000 files is reached. Above this relative threshold, if we add more entities in the same subdirectory then the memory leakage is increased again, AND FINALLY,
        • if we add more entities in any other subdirectory below the described relative threshold, then there is no leakage observed. In other words, we create (relatively speaking) 10`000 files in the root, then we can add up to 9`000 in each subdirectory without memory leakage;
      • On Transaction destroy there is no memory leakage;

      Despite these observations and strange "workarounds", obviously we CAN NOT use Subversion in productions conditions. So we hope you will find a way to fix these issues.

      Sample code for reproduction

      #define MAX_LOOP   10000

      svn_error_t*  test_func(const char* _szRepository_path
                            , apr_pool_t*     pool)
      {
          svn_repos_t*    repos;
          svn_fs_t*       fs;

          SVN_ERR(svn_repos_open3(&repos, _szRepository_path, NULL, pool, pool));
          fs = svn_repos_fs(repos);

          apr_pool_t*    subpool = svn_pool_create(pool);

          for (int i = 0; i < MAX_LOOP; i++) {
              svn_fs_txn_t*   txn;
              svn_fs_root_t*  txn_root;
              svn_revnum_t    youngest;
              const char*     txn_id = NULL;

           

              svn_pool_clear(subpool);
             
              SVN_ERR(svn_fs_youngest_rev(&youngest, fs, subpool));

              SVN_ERR(svn_repos_fs_begin_txn_for_commit (&txn
                                                   , repos
                                                   , youngest
                                                   , "user_name"
                                                   , "comment default"
                                                   , subpool));

              //---- Create unique file name and add to "/" in repository
              SVN_ERR(svn_fs_txn_root(&txn_root, txn, subpool));
              const char* pszFile_name = create_unique_file_name (subpool);
              SVN_ERR(svn_fs_make_file(txn_root, pszFile_name, subpool));

              if ((i % 100) == 0)
                  printf ("added: %d\n", i+1);

              const char* conflict = NULL;
              svn_revnum_t new_rev = SVN_INVALID_REVNUM;
            
              SVN_ERR(svn_fs_commit_txn(&conflict, &new_rev, txn, subpool));

              if (!SVN_IS_VALID_REVNUM(new_rev))

                  return svn_error_create(SVN_ERR_FS_GENERAL, NULL,
                                          "Commit failed...");

          }

          svn_pool_destroy(subpool);

          return SVN_NO_ERROR;

      }

      Attachments

        1. issue-4796-test-1.patch
          3 kB
          Julian Foad

        Activity

          People

            Unassigned Unassigned
            binetix BINETIX SUPPORT TEAM
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: