1
1
using System ;
2
2
using System . Collections . Generic ;
3
- using System . Diagnostics ;
4
3
using System . IO ;
5
4
using System . Linq ;
6
5
using System . Runtime . InteropServices ;
@@ -17,6 +16,8 @@ public abstract class Filter : IEquatable<Filter>
17
16
{
18
17
private static readonly LambdaEqualityHelper < Filter > equalityHelper =
19
18
new LambdaEqualityHelper < Filter > ( x => x . Name , x => x . Attributes ) ;
19
+ // 64K is optimal buffer size per https://technet.microsoft.com/en-us/library/cc938632.aspx
20
+ private const int BufferSize = 64 * 1024 ;
20
21
21
22
private readonly string name ;
22
23
private readonly IEnumerable < FilterAttributeEntry > attributes ;
@@ -51,6 +52,7 @@ protected Filter(string name, IEnumerable<FilterAttributeEntry> attributes)
51
52
private IntPtr thisPtr ;
52
53
private IntPtr nextPtr ;
53
54
private FilterSource filterSource ;
55
+ private Stream output ;
54
56
55
57
/// <summary>
56
58
/// The name that this filter was registered with
@@ -80,7 +82,7 @@ internal GitFilter GitFilter
80
82
/// Complete callback on filter
81
83
///
82
84
/// This optional callback will be invoked when the upstream filter is
83
- /// closed. Gives the filter a change to perform any final actions or
85
+ /// closed. Gives the filter a chance to perform any final actions or
84
86
/// necissary clean up.
85
87
/// </summary>
86
88
/// <param name="path">The path of the file being filtered</param>
@@ -224,6 +226,7 @@ int StreamCreateCallback(out IntPtr git_writestream_out, GitFilter self, IntPtr
224
226
nextStream = new GitWriteStream ( ) ;
225
227
Marshal . PtrToStructure ( nextPtr , nextStream ) ;
226
228
filterSource = FilterSource . FromNativePtr ( filterSourcePtr ) ;
229
+ output = new WriteStream ( nextStream , nextPtr ) ;
227
230
}
228
231
catch ( Exception exception )
229
232
{
@@ -254,20 +257,10 @@ int StreamCloseCallback(IntPtr stream)
254
257
Ensure . ArgumentNotZeroIntPtr ( stream , "stream" ) ;
255
258
Ensure . ArgumentIsExpectedIntPtr ( stream , thisPtr , "stream" ) ;
256
259
257
- string tempFileName = Path . GetTempFileName ( ) ;
258
- // Setup a file system backed write-to stream to work with this gives the runtime
259
- // somewhere to put bits if the amount of data could cause an OOM scenario.
260
- using ( FileStream output = File . Open ( tempFileName , FileMode . Open , FileAccess . Write , FileShare . ReadWrite ) )
261
- // Setup a septerate read-from stream on the same file system backing
262
- // a seperate stream helps avoid a flush to disk when reading the written content
263
- using ( FileStream reader = File . Open ( tempFileName , FileMode . Open , FileAccess . Read , FileShare . ReadWrite ) )
260
+ using ( BufferedStream outputBuffer = new BufferedStream ( output , BufferSize ) )
264
261
{
265
- Complete ( filterSource . Path , filterSource . Root , output ) ;
266
- output . Flush ( ) ;
267
- WriteToNextFilter ( reader ) ;
262
+ Complete ( filterSource . Path , filterSource . Root , outputBuffer ) ;
268
263
}
269
- // clean up after outselves
270
- File . Delete ( tempFileName ) ;
271
264
}
272
265
catch ( Exception exception )
273
266
{
@@ -310,53 +303,22 @@ unsafe int StreamWriteCallback(IntPtr stream, IntPtr buffer, UIntPtr len)
310
303
311
304
string tempFileName = Path . GetTempFileName ( ) ;
312
305
using ( UnmanagedMemoryStream input = new UnmanagedMemoryStream ( ( byte * ) buffer . ToPointer ( ) , ( long ) len ) )
313
- // Setup a file system backed write-to stream to work with this gives the runtime
314
- // somewhere to put bits if the amount of data could cause an OOM scenario.
315
- using ( FileStream output = File . Open ( tempFileName , FileMode . Open , FileAccess . Write , FileShare . ReadWrite ) )
316
- // Setup a septerate read-from stream on the same file system backing
317
- // a seperate stream helps avoid a flush to disk when reading the written content
318
- using ( FileStream reader = File . Open ( tempFileName , FileMode . Open , FileAccess . Read , FileShare . ReadWrite ) )
306
+ using ( BufferedStream outputBuffer = new BufferedStream ( output , BufferSize ) )
319
307
{
320
308
switch ( filterSource . SourceMode )
321
309
{
322
310
case FilterMode . Clean :
323
- try
324
- {
325
- Clean ( filterSource . Path , filterSource . Root , input , output ) ;
326
- }
327
- catch ( Exception exception )
328
- {
329
- Log . Write ( LogLevel . Error , "Filter.StreamWriteCallback exception" ) ;
330
- Log . Write ( LogLevel . Error , exception . ToString ( ) ) ;
331
- Proxy . giterr_set_str ( GitErrorCategory . Filter , exception ) ;
332
- result = ( int ) GitErrorCode . Error ;
333
- }
311
+ Clean ( filterSource . Path , filterSource . Root , input , outputBuffer ) ;
334
312
break ;
335
313
336
314
case FilterMode . Smudge :
337
- try
338
- {
339
- Smudge ( filterSource . Path , filterSource . Root , input , output ) ;
340
- }
341
- catch ( Exception exception )
342
- {
343
- Log . Write ( LogLevel . Error , "Filter.StreamWriteCallback exception" ) ;
344
- Log . Write ( LogLevel . Error , exception . ToString ( ) ) ;
345
- Proxy . giterr_set_str ( GitErrorCategory . Filter , exception ) ;
346
- result = ( int ) GitErrorCode . Error ;
347
- }
315
+ Smudge ( filterSource . Path , filterSource . Root , input , outputBuffer ) ;
348
316
break ;
317
+
349
318
default :
350
319
Proxy . giterr_set_str ( GitErrorCategory . Filter , "Unexpected filter mode." ) ;
351
320
return ( int ) GitErrorCode . Ambiguous ;
352
321
}
353
-
354
- if ( result == ( int ) GitErrorCode . Ok )
355
- {
356
- // have to flush the write-to stream to enable the read stream to get access to the bits
357
- output . Flush ( ) ;
358
- result = WriteToNextFilter ( reader ) ;
359
- }
360
322
}
361
323
362
324
// clean up after outselves
@@ -372,37 +334,5 @@ unsafe int StreamWriteCallback(IntPtr stream, IntPtr buffer, UIntPtr len)
372
334
373
335
return result ;
374
336
}
375
-
376
- private unsafe int WriteToNextFilter ( Stream output )
377
- {
378
- // 64K is optimal buffer size per https://technet.microsoft.com/en-us/library/cc938632.aspx
379
- const int BufferSize = 64 * 1024 ;
380
-
381
- Debug . Assert ( output != null , "output parameter is null" ) ;
382
- Debug . Assert ( output . CanRead , "output.CanRead parameter equals false" ) ;
383
-
384
- int result = 0 ;
385
- byte [ ] bytes = new byte [ BufferSize ] ;
386
- IntPtr bytesPtr = Marshal . AllocHGlobal ( BufferSize ) ;
387
- try
388
- {
389
- int read = 0 ;
390
- while ( ( read = output . Read ( bytes , 0 , bytes . Length ) ) > 0 )
391
- {
392
- Marshal . Copy ( bytes , 0 , bytesPtr , read ) ;
393
- if ( ( result = nextStream . write ( nextPtr , bytesPtr , ( UIntPtr ) read ) ) != ( int ) GitErrorCode . Ok )
394
- {
395
- Proxy . giterr_set_str ( GitErrorCategory . Filter , "Filter write to next stream failed" ) ;
396
- break ;
397
- }
398
- }
399
- }
400
- finally
401
- {
402
- Marshal . FreeHGlobal ( bytesPtr ) ;
403
- }
404
-
405
- return result ;
406
- }
407
337
}
408
338
}
0 commit comments