Skip to content

Commit 6412711

Browse files
authored
Exposed MaxListingConcurrency so the initial phase of the transfer can be sped up (#226)
* Exposed MaxListingConcurrency so the intial phase of the transfer can be sped up * Made the config value optional so the existing values can be preserved * PR feedback * No need to duplicate values
1 parent 9b12ee1 commit 6412711

File tree

5 files changed

+105
-61
lines changed

5 files changed

+105
-61
lines changed

lib/Resources.Designer.cs

Lines changed: 10 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/Resources.resx

Lines changed: 30 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<root>
3-
<!--
4-
Microsoft ResX Schema
5-
3+
<!--
4+
Microsoft ResX Schema
5+
66
Version 2.0
7-
8-
The primary goals of this format is to allow a simple XML format
9-
that is mostly human readable. The generation and parsing of the
10-
various data types are done through the TypeConverter classes
7+
8+
The primary goals of this format is to allow a simple XML format
9+
that is mostly human readable. The generation and parsing of the
10+
various data types are done through the TypeConverter classes
1111
associated with the data types.
12-
12+
1313
Example:
14-
14+
1515
... ado.net/XML headers & schema ...
1616
<resheader name="resmimetype">text/microsoft-resx</resheader>
1717
<resheader name="version">2.0</resheader>
@@ -26,36 +26,36 @@
2626
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
2727
<comment>This is a comment</comment>
2828
</data>
29-
30-
There are any number of "resheader" rows that contain simple
29+
30+
There are any number of "resheader" rows that contain simple
3131
name/value pairs.
32-
33-
Each data row contains a name, and value. The row also contains a
34-
type or mimetype. Type corresponds to a .NET class that support
35-
text/value conversion through the TypeConverter architecture.
36-
Classes that don't support this are serialized and stored with the
32+
33+
Each data row contains a name, and value. The row also contains a
34+
type or mimetype. Type corresponds to a .NET class that support
35+
text/value conversion through the TypeConverter architecture.
36+
Classes that don't support this are serialized and stored with the
3737
mimetype set.
38-
39-
The mimetype is used for serialized objects, and tells the
40-
ResXResourceReader how to depersist the object. This is currently not
38+
39+
The mimetype is used for serialized objects, and tells the
40+
ResXResourceReader how to depersist the object. This is currently not
4141
extensible. For a given mimetype the value must be set accordingly:
42-
43-
Note - application/x-microsoft.net.object.binary.base64 is the format
44-
that the ResXResourceWriter will generate, however the reader can
42+
43+
Note - application/x-microsoft.net.object.binary.base64 is the format
44+
that the ResXResourceWriter will generate, however the reader can
4545
read any of the formats listed below.
46-
46+
4747
mimetype: application/x-microsoft.net.object.binary.base64
48-
value : The object must be serialized with
48+
value : The object must be serialized with
4949
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
5050
: and then encoded with base64 encoding.
51-
51+
5252
mimetype: application/x-microsoft.net.object.soap.base64
53-
value : The object must be serialized with
53+
value : The object must be serialized with
5454
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
5555
: and then encoded with base64 encoding.
5656
5757
mimetype: application/x-microsoft.net.object.bytearray.base64
58-
value : The object must be serialized into a byte array
58+
value : The object must be serialized into a byte array
5959
: using a System.ComponentModel.TypeConverter
6060
: and then encoded with base64 encoding.
6161
-->
@@ -222,6 +222,9 @@ MD5 in property: {2}</value>
222222
<data name="ParallelCountNotPositiveException" xml:space="preserve">
223223
<value>Parallel operations count must be positive.</value>
224224
</data>
225+
<data name="MaxListingConcurrencyNotPositiveException" xml:space="preserve">
226+
<value>Max listing concurrency must be positive.</value>
227+
</data>
225228
<data name="ParameterCannotBeNullException" xml:space="preserve">
226229
<value>{0} cannot be null.</value>
227230
<comment>{0} is the property or parameter name.</comment>

lib/TransferConfigurations.cs

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,18 @@ public class TransferConfigurations
3232
/// </summary>
3333
private long maximumCacheSize;
3434

35+
/// <summary>
36+
/// How many listings can be performed in parallel.
37+
/// </summary>
38+
private int? maxListingConcurrency;
39+
3540
/// <summary>
3641
/// Instance to call native methods to get current memory status.
3742
/// </summary>
3843
private GlobalMemoryStatusNativeMethods memStatus = new GlobalMemoryStatusNativeMethods();
3944

4045
/// <summary>
41-
/// Initializes a new instance of the
46+
/// Initializes a new instance of the
4247
/// <see cref="TransferConfigurations" /> class.
4348
/// </summary>
4449
public TransferConfigurations()
@@ -52,12 +57,12 @@ public TransferConfigurations()
5257
}
5358

5459
/// <summary>
55-
/// Gets or sets a value indicating how many work items to process
56-
/// concurrently. Downloading or uploading a single blob can consist
60+
/// Gets or sets a value indicating how many work items to process
61+
/// concurrently. Downloading or uploading a single blob can consist
5762
/// of a large number of work items.
5863
/// </summary>
5964
/// <value>How many work items to process concurrently.</value>
60-
public int ParallelOperations
65+
public int ParallelOperations
6166
{
6267
get
6368
{
@@ -78,10 +83,24 @@ public int ParallelOperations
7883
}
7984
}
8085

86+
public int? MaxListingConcurrency
87+
{
88+
get
89+
{
90+
return this.maxListingConcurrency;
91+
}
92+
set
93+
{
94+
if (value <= 0)
95+
throw new ArgumentException(string.Format((IFormatProvider) CultureInfo.CurrentCulture, Resources.MaxListingConcurrencyNotPositiveException));
96+
this.maxListingConcurrency = value;
97+
}
98+
}
99+
81100
/// <summary>
82-
/// Gets or sets the BlockSize to use for Windows Azure Storage transfers to block blob(s).
101+
/// Gets or sets the BlockSize to use for Windows Azure Storage transfers to block blob(s).
83102
/// It must be between 4MB and 100MB and be multiple of 4MB.
84-
///
103+
///
85104
/// Currently, the max block count of a block blob is limited to 50000.
86105
/// When transfering a big file and the BlockSize provided is smaller than the minimum value - (size/50000),
87106
/// it'll be reset to a value which is greater than the minimum value and multiple of 4MB for this file.
@@ -123,7 +142,7 @@ public int BlockSize
123142
public string UserAgentPrefix
124143
{
125144
get;
126-
set;
145+
set;
127146
}
128147

129148
/// <summary>

lib/TransferJobs/HierarchyDirectoryTransfer.cs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ namespace Microsoft.Azure.Storage.DataMovement
2424
/// <summary>
2525
/// Represents a hierarchy directory transfer operation.
2626
/// In a flat directory transfer, the enumeration only returns file entries and it only transfers files under the directory.
27-
///
28-
/// In a hierarchy directory transfer, the enumeration also returns directory entries,
27+
///
28+
/// In a hierarchy directory transfer, the enumeration also returns directory entries,
2929
/// it transfers files under the directory and also handles opertions on directories.
3030
/// </summary>
3131
#if BINARY_SERIALIZATION
@@ -63,6 +63,7 @@ private ConcurrentDictionary<SubDirectoryTransfer, object> ongoingSubDirTransfer
6363
private SemaphoreSlim maxConcurrencyControl = null;
6464

6565
private int maxConcurrency = 0;
66+
private int? maxListingConcurrency = 0;
6667

6768
object continuationTokenLock = new object();
6869

@@ -81,7 +82,7 @@ private ConcurrentDictionary<SubDirectoryTransfer, object> ongoingSubDirTransfer
8182

8283
private DirectoryListingScheduler directoryListingScheduler = null;
8384

84-
private AzureFileDirectorySDDLCache azureFileDirectorySDDLCache = new AzureFileDirectorySDDLCache();
85+
private AzureFileDirectorySDDLCache azureFileDirectorySDDLCache = new AzureFileDirectorySDDLCache();
8586

8687
#if !BINARY_SERIALIZATION
8788
[DataMember]
@@ -283,6 +284,14 @@ public override int MaxTransferConcurrency
283284
}
284285
}
285286

287+
public int? MaxListingConcurrency
288+
{
289+
set
290+
{
291+
this.maxListingConcurrency = value;
292+
}
293+
}
294+
286295
public AzureFileDirectorySDDLCache SDDLCache
287296
{
288297
get
@@ -405,7 +414,8 @@ private void ResetExecutionStatus()
405414
#endif
406415
}
407416

408-
directoryListingScheduler = new DirectoryListingScheduler(maxListingThreadCount);
417+
418+
directoryListingScheduler = new DirectoryListingScheduler(this.maxListingConcurrency ?? maxListingThreadCount);
409419
}
410420

411421
public override async Task ExecuteInternalAsync(TransferScheduler scheduler, CancellationToken cancellationToken)
@@ -537,7 +547,7 @@ internal async void TransferFile(SingleObjectTransfer transferItem, TransferSche
537547
TransferErrorCode.FailToEnumerateDirectory,
538548
string.Format(CultureInfo.CurrentCulture,
539549
Resources.EnumerateDirectoryException,
540-
this.Destination.Instance.ConvertToString()),
550+
this.Destination.Instance.ConvertToString()),
541551
ex.InnerException);
542552
}
543553

@@ -867,7 +877,7 @@ protected TransferEntry CreateDirectoryTransferEntry(string relativePath)
867877
else if (this.Source.Type == TransferLocationType.LocalDirectory)
868878
{
869879
return new DirectoryEntry
870-
(relativePath,
880+
(relativePath,
871881
LongPath.Combine(this.Source.Instance as string, relativePath), null);
872882
}
873883
else

lib/TransferManager.cs

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public static class TransferManager
3131
/// Transfer scheduler that schedules execution of transfer jobs
3232
/// </summary>
3333
private static TransferScheduler scheduler = new TransferScheduler(configurations);
34-
34+
3535
/// <summary>
3636
/// Stores all running transfers
3737
/// </summary>
@@ -93,7 +93,7 @@ public static Task UploadAsync(string sourcePath, CloudBlob destBlob, UploadOpti
9393
if (options != null)
9494
{
9595
destLocation.AccessCondition = options.DestinationAccessCondition;
96-
}
96+
}
9797

9898
return UploadInternalAsync(sourceLocation, destLocation, options, context, cancellationToken);
9999
}
@@ -571,7 +571,7 @@ public static Task DownloadAsync(CloudFile sourceFile, Stream destStream, Downlo
571571
{
572572
AzureFileLocation sourceLocation = new AzureFileLocation(sourceFile);
573573
StreamLocation destLocation = new StreamLocation(destStream);
574-
574+
575575
// Set default request options
576576
SetDefaultRequestOptions(sourceLocation);
577577

@@ -611,7 +611,7 @@ public static Task<TransferStatus> DownloadDirectoryAsync(CloudBlobDirectory sou
611611
AzureBlobDirectoryLocation sourceLocation = new AzureBlobDirectoryLocation(sourceBlobDir);
612612
DirectoryLocation destLocation = new DirectoryLocation(destPath);
613613
AzureBlobEnumerator sourceEnumerator = new AzureBlobEnumerator(sourceLocation);
614-
614+
615615
// Set default request options
616616
SetDefaultRequestOptions(sourceLocation);
617617

@@ -659,7 +659,7 @@ public static async Task<TransferStatus> DownloadDirectoryAsync(CloudFileDirecto
659659

660660
if (options != null)
661661
{
662-
TransferManager.CheckSearchPatternOfAzureFileSource(options);
662+
TransferManager.CheckSearchPatternOfAzureFileSource(options);
663663
sourceLocation.FileRequestOptions.DisableContentMD5Validation = options.DisableContentMD5Validation;
664664
FileSecurityOperations.EnableRequiredPrivileges(options.PreserveSMBPermissions, true);
665665
}
@@ -832,11 +832,11 @@ public static Task CopyAsync(CloudBlob sourceBlob, CloudFile destFile, bool isSe
832832
/// <returns>A <see cref="Task"/> object that represents the asynchronous operation.</returns>
833833
[Obsolete("Replaced by overload that takes CopyMethod", false)]
834834
public static Task CopyAsync(
835-
CloudBlob sourceBlob,
836-
CloudFile destFile,
837-
bool isServiceCopy,
838-
CopyOptions options,
839-
SingleTransferContext context,
835+
CloudBlob sourceBlob,
836+
CloudFile destFile,
837+
bool isServiceCopy,
838+
CopyOptions options,
839+
SingleTransferContext context,
840840
CancellationToken cancellationToken)
841841
{
842842
return CopyAsync(sourceBlob, destFile, isServiceCopy ? CopyMethod.ServiceSideAsyncCopy : CopyMethod.SyncCopy, options, context, cancellationToken);
@@ -1294,8 +1294,8 @@ public static Task<TransferStatus> CopyDirectoryAsync(CloudBlobDirectory sourceB
12941294
sourceBlobDir,
12951295
destBlobDir,
12961296
isServiceCopy ? CopyMethod.ServiceSideAsyncCopy : CopyMethod.SyncCopy,
1297-
options,
1298-
context,
1297+
options,
1298+
context,
12991299
cancellationToken);
13001300
}
13011301

@@ -1673,7 +1673,7 @@ private static async Task<TransferStatus> DownloadDirectoryInternalAsync(Transfe
16731673
hierarchyDirectoryTransfer.Recursive = options.Recursive;
16741674
}
16751675
}
1676-
1676+
16771677
if (transfer.SourceEnumerator == null || !AreSameTransferEnumerators(transfer.SourceEnumerator, sourceEnumerator))
16781678
{
16791679
transfer.SourceEnumerator = sourceEnumerator;
@@ -1685,12 +1685,12 @@ private static async Task<TransferStatus> DownloadDirectoryInternalAsync(Transfe
16851685
}
16861686

16871687
private static async Task<TransferStatus> CopyDirectoryInternalAsync(
1688-
TransferLocation sourceLocation,
1689-
TransferLocation destLocation,
1690-
TransferMethod transferMethod,
1691-
ITransferEnumerator sourceEnumerator,
1692-
CopyDirectoryOptions options,
1693-
DirectoryTransferContext context,
1688+
TransferLocation sourceLocation,
1689+
TransferLocation destLocation,
1690+
TransferMethod transferMethod,
1691+
ITransferEnumerator sourceEnumerator,
1692+
CopyDirectoryOptions options,
1693+
DirectoryTransferContext context,
16941694
CancellationToken cancellationToken)
16951695
{
16961696
DirectoryTransfer transfer = GetOrCreateDirectoryTransfer(sourceLocation, destLocation, transferMethod, context);
@@ -1782,7 +1782,10 @@ private static DirectoryTransfer GetOrCreateDirectoryTransfer(TransferLocation s
17821782
if ((sourceLocation.Type == TransferLocationType.AzureFileDirectory)
17831783
|| ((sourceLocation.Type == TransferLocationType.LocalDirectory) && (destLocation.Type == TransferLocationType.AzureFileDirectory)))
17841784
{
1785-
directoryTransfer = new HierarchyDirectoryTransfer(sourceLocation, destLocation, transferMethod);
1785+
directoryTransfer = new HierarchyDirectoryTransfer(sourceLocation, destLocation, transferMethod)
1786+
{
1787+
MaxListingConcurrency = configurations.MaxListingConcurrency
1788+
};
17861789
}
17871790
else
17881791
{

0 commit comments

Comments
 (0)