Skip to content

Commit ae65478

Browse files
committed
Fix for computing blob size without loading entire blob content in memory - Fix libgit2#873
1 parent e310401 commit ae65478

File tree

7 files changed

+91
-0
lines changed

7 files changed

+91
-0
lines changed

LibGit2Sharp.Tests/ObjectDatabaseFixture.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,25 @@ public void CanCreateABlobFromAFileInTheWorkingDirectory()
4848
}
4949
}
5050

51+
[Fact]
52+
public void RetrieveObjectMetadataReturnsCorrectSizeAndTypeForBlob()
53+
{
54+
string path = InitNewRepository();
55+
56+
using (var repo = new Repository(path))
57+
{
58+
Blob blob = CreateBlob(repo, "I'm a new file\n");
59+
Assert.NotNull(blob);
60+
61+
GitObjectMetadata blobMetadata = repo.ObjectDatabase.RetrieveObjectMetadata(blob.Id);
62+
Assert.Equal(blobMetadata.Size, blob.Size);
63+
Assert.Equal(blobMetadata.Type, ObjectType.Blob);
64+
65+
Blob fetchedBlob = repo.Lookup<Blob>(blob.Id);
66+
Assert.Equal(blobMetadata.Size, fetchedBlob.Size);
67+
}
68+
}
69+
5170
[Fact]
5271
public void CanCreateABlobIntoTheDatabaseOfABareRepository()
5372
{

LibGit2Sharp/Blob.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ internal Blob(Repository repo, ObjectId id)
2727

2828
/// <summary>
2929
/// Gets the size in bytes of the raw content of a blob.
30+
/// <para> Please note that this would load entire blob content in the memory to compute the Size.
31+
/// In order to read blob size from header, Repository.ObjectMetadata.RetrieveObjectMetadata(Blob.Id).Size
32+
/// can be used.
33+
/// </para>
3034
/// </summary>
3135
public virtual int Size { get { return (int)lazySize.Value; } }
3236

LibGit2Sharp/Core/NativeMethods.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -754,6 +754,9 @@ internal static extern int git_odb_foreach(
754754
[DllImport(libgit2)]
755755
internal static extern void git_odb_free(IntPtr odb);
756756

757+
[DllImport(libgit2)]
758+
internal static extern int git_odb_read_header(out UIntPtr len_out, out GitObjectType type, ObjectDatabaseSafeHandle odb, ref GitOid id);
759+
757760
[DllImport(libgit2)]
758761
internal static extern void git_object_free(IntPtr obj);
759762

LibGit2Sharp/Core/Proxy.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1378,6 +1378,21 @@ public static bool git_odb_exists(ObjectDatabaseSafeHandle odb, ObjectId id)
13781378
}
13791379
}
13801380

1381+
public static GitObjectMetadata git_odb_read_header(ObjectDatabaseSafeHandle odb, ObjectId id)
1382+
{
1383+
using (ThreadAffinity())
1384+
{
1385+
GitOid oid = id.Oid;
1386+
UIntPtr length;
1387+
GitObjectType objectType;
1388+
1389+
int res = NativeMethods.git_odb_read_header(out length, out objectType, odb, ref oid);
1390+
Ensure.ZeroResult(res);
1391+
1392+
return new GitObjectMetadata((long)length, objectType);
1393+
}
1394+
}
1395+
13811396
public static ICollection<TResult> git_odb_foreach<TResult>(
13821397
ObjectDatabaseSafeHandle odb,
13831398
Func<IntPtr, TResult> resultSelector)

LibGit2Sharp/GitObjectMetadata.cs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using LibGit2Sharp.Core;
2+
using System;
3+
4+
namespace LibGit2Sharp
5+
{
6+
/// <summary>
7+
/// Exposes low level Git object metadata
8+
/// </summary>
9+
public sealed class GitObjectMetadata
10+
{
11+
private readonly GitObjectType type;
12+
13+
/// <summary>
14+
/// Size of the Object
15+
/// </summary>
16+
public long Size { get; private set; }
17+
18+
/// <summary>
19+
/// Object Type
20+
/// </summary>
21+
public ObjectType Type
22+
{
23+
get
24+
{
25+
return type.ToObjectType();
26+
}
27+
}
28+
29+
internal GitObjectMetadata(long size, GitObjectType type)
30+
{
31+
this.Size = size;
32+
this.type = type;
33+
}
34+
}
35+
}

LibGit2Sharp/LibGit2Sharp.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@
9595
<Compile Include="MergeOptions.cs" />
9696
<Compile Include="MergeResult.cs" />
9797
<Compile Include="NotFoundException.cs" />
98+
<Compile Include="GitObjectMetadata.cs" />
9899
<Compile Include="PatchEntryChanges.cs" />
99100
<Compile Include="PatchStats.cs" />
100101
<Compile Include="PullOptions.cs" />

LibGit2Sharp/ObjectDatabase.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,20 @@ public virtual bool Contains(ObjectId objectId)
7272
return Proxy.git_odb_exists(handle, objectId);
7373
}
7474

75+
/// <summary>
76+
/// Retrieves the header of a GitObject from the object database. The header contains the Size
77+
/// and Type of the object. Note that most backends do not support reading only the header
78+
/// of an object, so the whole object will be read and then size would be returned.
79+
/// </summary>
80+
/// <param name="objectId">Object Id of the queried object</param>
81+
/// <returns>GitObjectMetadata object instance containg object header information</returns>
82+
public virtual GitObjectMetadata RetrieveObjectMetadata(ObjectId objectId)
83+
{
84+
Ensure.ArgumentNotNull(objectId, "objectId");
85+
86+
return Proxy.git_odb_read_header(handle, objectId);
87+
}
88+
7589
/// <summary>
7690
/// Inserts a <see cref="Blob"/> into the object database, created from the content of a file.
7791
/// </summary>

0 commit comments

Comments
 (0)