libgit2 / libgit2/libgit2sharp

Parallel calls to Repository.ObjectDatabase.CreateBlob with identical contents fails.

Aberta
#1,122 2 comentários 0 reações 0 responsáveis Ver no GitHub

Ninguém assumiu esta issue ainda.

Linguagem predominante
C#
Estrelas
3.5k
Forks
925
Métricas de merge de PRs
Nenhum PR com merge em 30d

Descrição

I would like to insert blobs from memory into an object database in parallel (based on the technique described at http://stackoverflow.com/a/16244234). This works fine most of the time, but is subject to race conditions if the contents are the same. There are two classes of errors I observe:
1. Exception due to FILE_EXISTS conflict when trying to create the directory with the first two characters of the OID under objects.
2. NULL blob returned from CreateBlob.

Here's some example code to reproduce the problem:

using System;
using System.Text;
using System.IO;
using System.Threading.Tasks;
using LibGit2Sharp;

namespace GitODBStress
{
    class Program
    {
        static void Main()
        {

            string repoPath = Path.Combine(Path.GetTempPath(), "Git_Parallel_Odb");
            int iterationCount = 100;

            if (!Directory.Exists(repoPath))
            {
                Directory.CreateDirectory(repoPath);
            }

            var path = Repository.Init(repoPath, isBare:true);
            Console.WriteLine("Made repo at {0}", path);

            var repo = new Repository(path);

            var tasks = new Task[2];
            for (int i = 0; i < iterationCount; ++i)
            {
                var iter = i;
                byte[] buf = Encoding.ASCII.GetBytes("foo" + iter.ToString());
                for (int taskNo = 0; taskNo < 2; ++taskNo)
                {
                    tasks[taskNo] = Task.Factory.StartNew(() =>
                        {
                            MemoryStream ms = new MemoryStream(buf);
                            for (; ; )
                            {
                                try
                                {
                                    var blob = repo.ObjectDatabase.CreateBlob(ms);
                                    if (blob == null)
                                    {
                                        Console.WriteLine("ERROR: NULL blob on iteration {0}", iter);
                                        continue;
                                    }

                                    break;
                                }
                                catch (LibGit2SharpException e)
                                {
                                    Console.WriteLine("ERROR: Caught LibGit2SharpException on iteration {0}: {1}", iter, e.Message);
                                    if (e.Message.Contains("Cannot create a file when that file already exists."))
                                    {
                                        continue;
                                    }
                                }
                            }
                        });
                }

                Task.WaitAll(tasks);
            }

            repo.Dispose();

            // clean up temp repo files
            var files = Directory.GetFiles(repoPath, "*.*", SearchOption.AllDirectories);
            foreach (var f in files)
            {
                var attrib = File.GetAttributes(f);
                if (attrib.HasFlag(FileAttributes.ReadOnly))
                {
                    File.SetAttributes(f, attrib & ~FileAttributes.ReadOnly);
                }
            }

            Directory.Delete(repoPath, true);
        }
    }
}

Thanks!

Guia de contribuição

Abrir o guia de contribuição

Primeiros passos

  1. Leia a issue inteira e depois o guia de contribuição do projeto.
  2. Comente na issue dizendo que vai assumir — evita que duas pessoas façam o mesmo trabalho.
  3. Faça um fork do repositório e trabalhe em uma branch.
  4. Abra um pull request que referencie o número da issue.

Direção de pesquisa

Comece em Repository.ObjectDatabase.CreateBlob e execute a reprodução em C# em um repositório bare. Rastreie o caminho paralelo para conteúdos idênticos e os resultados FILE_EXISTS e null-blob relatados. Está concluído quando as chamadas concorrentes forem concluídas sem nenhuma das duas falhas ao criar o blob esperado.

Escrita pelo modelo de indexação a partir do texto da issue.

Avaliação

Stack de tecnologia
csharp, git
Domínio
databases
Tipo de issue
Bug
Dificuldade
4/5
Tempo estimado
3-5 dias
Status de atividade
Estagnada
Clareza
Razoavelmente clara
Facilidade para iniciantes
35/100

Receba novas issues na sua caixa de entrada

Um resumo curto de issues do GitHub para quem está começando.