Skip to content

Commit fd810b6

Browse files
authored
Merge pull request #10 from dgw-dev/dw_main_dev
request size control
2 parents a6222a6 + 89755d3 commit fd810b6

11 files changed

Lines changed: 120 additions & 62 deletions

File tree

DbLocalizer.Tests/appsettings.Test.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@
88
}
99
},
1010
"ConnectionStrings": {
11-
"LocalizationTest": "Server=localhost;Initial Catalog=LocalizationTest;User Id={0};Password={1};MultipleActiveResultSets=True;TrustServerCertificate=True"
11+
"LocalizationTest": "Server={0};Initial Catalog={1};User Id={2};Password={3};MultipleActiveResultSets=True;TrustServerCertificate=True"
1212
},
1313
"UseScheduler": "false",
1414
"ScheduledExportCron": "0 0 6 ? * MON *",
1515
"ScheduledImportPurgeCron": "0 0 6 ? * FRI *",
1616
"ImportMaxTablesPerFile": "20",
1717
"ExportMaxTablesPerFile": "20",
18-
"MaxRowsPerFile": "1000",
18+
"MaxRowsPerTable": "1000",
1919
"ExportLookbackInDays": "5000",
2020
"MaximumRequestSize": "10485760", // 10MB in bytes
2121
"DataToPurgeInDays": "60",

DbLocalizer/appsettings.Development.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@
88
}
99
},
1010
"ConnectionStrings": {
11-
"LocalizationTest": "Server=localhost;Initial Catalog=LocalizationTest;User Id={0};Password={1};MultipleActiveResultSets=True;TrustServerCertificate=True"
11+
"LocalizationTest": "Server={0};Initial Catalog={1};User Id={2};Password={3};MultipleActiveResultSets=True;TrustServerCertificate=True"
1212
},
1313
"UseScheduler": "false",
1414
"ScheduledExportCron": "0 0 6 ? * MON *",
1515
"ScheduledImportPurgeCron": "0 0 6 ? * FRI *",
1616
"ImportMaxTablesPerFile": "20",
1717
"ExportMaxTablesPerFile": "20",
18-
"MaxRowsPerFile": "1000",
18+
"MaxRowsPerTable": "500",
1919
"ExportLookbackInDays": "5000",
2020
"MaximumRequestSize": "10485760", // 10MB in bytes
2121
"DataToPurgeInDays": "60",

DbLocalizer/appsettings.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@
88
}
99
},
1010
"ConnectionStrings": {
11-
"LocalizationTest": "Server=localhost;Initial Catalog=LocalizationTest;User Id={0};Password={1};MultipleActiveResultSets=True;TrustServerCertificate=True"
11+
"LocalizationTest": "Server={0};Initial Catalog={1};User Id={2};Password={3};MultipleActiveResultSets=True;TrustServerCertificate=True"
1212
},
1313
"UseScheduler": "false",
1414
"ScheduledExportCron": "0 0 6 ? * MON *",
1515
"ScheduledImportPurgeCron": "0 0 6 ? * FRI *",
1616
"ImportMaxTablesPerFile": "20",
1717
"ExportMaxTablesPerFile": "20",
18-
"MaxRowsPerFile": "1000",
18+
"MaxRowsPerTable": "1000",
1919
"ExportLookbackInDays": "5000",
2020
"MaximumRequestSize": "10485760", // 10MB in bytes
2121
"DataToPurgeInDays": "60",

DbLocalizer/logs.db

0 Bytes
Binary file not shown.

Entities/AppSettings.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ public class AppSettings
77
public string ScheduledImportPurgeCron { get; set; }
88
public string ImportMaxTablesPerFile { get; set; }
99
public string ExportMaxTablesPerFile { get; set; }
10-
public string MaxRowsPerFile { get; set; }
10+
public string MaxRowsPerTable { get; set; }
1111
public string ExportLookbackInDays { get; set; }
1212
public string MaximumRequestSize { get; set; }
1313
public string DataToPurgeInDays { get; set; }

Entities/DAL/DbCredentialsManager.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ public class DbCredentialsManager
1010
private readonly Dictionary<string, DbCredentials> _dbCredentials = new Dictionary<string, DbCredentials>()
1111
{
1212
{
13-
"LocalizationTest", new DbCredentials() { Username = "LocalizationUser", Password = "@LocalizationTest#"}
13+
"LocalizationTest", new DbCredentials() { ServerName = "localhost", DatabaseName = "LocalizationTest", Username = "LocalizationUser", Password = "@LocalizationTest#"}
1414
}
1515
};
1616
public DbCredentials GetDbCredentials(string connectionStringName)
@@ -21,6 +21,8 @@ public DbCredentials GetDbCredentials(string connectionStringName)
2121

2222
public class DbCredentials
2323
{
24+
public string DatabaseName { get; set; }
25+
public string ServerName { get; set; }
2426
public string Username { get; set; }
2527
public string Password { get; set; }
2628
}

Entities/Databases.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,14 @@ private void BuildDatabases()
4141
string connectionString = _config.GetConnectionString(db.ConnectionStringName);
4242
DbCredentialsManager dbCredentialsManager = new DbCredentialsManager();
4343
DbCredentials dbCredentials = dbCredentialsManager.GetDbCredentials(db.ConnectionStringName);
44-
if (dbCredentials != null && !string.IsNullOrEmpty(dbCredentials.Username) && !string.IsNullOrEmpty(dbCredentials.Password) && !string.IsNullOrEmpty(connectionString))
44+
if (dbCredentials != null
45+
&& !string.IsNullOrEmpty(dbCredentials.ServerName)
46+
&& !string.IsNullOrEmpty(dbCredentials.DatabaseName)
47+
&& !string.IsNullOrEmpty(dbCredentials.Username)
48+
&& !string.IsNullOrEmpty(dbCredentials.Password)
49+
&& !string.IsNullOrEmpty(connectionString))
4550
{
46-
connectionString = string.Format(connectionString, dbCredentials.Username, dbCredentials.Password);
51+
connectionString = string.Format(connectionString, dbCredentials.ServerName, dbCredentials.DatabaseName, dbCredentials.Username, dbCredentials.Password);
4752
db.ConnectionStringValue = connectionString;
4853
db.CanConnect = DatabaseCanConnect(connectionString);
4954
_sqlSchemaBuilder.BuildDatabaseSchemaFiles(db);

Entities/Plugins/TranslationManagement/Smartling/ISmartlingExportFileProcessor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public interface ISmartlingExportFileProcessor
1414
string ExportType { get; set; }
1515
ICacheManager CacheManager { get; set; }
1616
Dictionary<string, List<DataSet>> DatabaseUpdatesForApp { get; set; }
17-
T ProcessExportData<T>(string exportLookbackInDays, int exportMaxTablesPerFile, int maxRowsPerFile, CancellationToken ct, Database db);
17+
T ProcessExportData<T>(string exportLookbackInDays, int exportMaxTablesPerFile, int maxRowsPerTable, CancellationToken ct, Database db);
1818
MultipartFormDataContent GetCultureContent(SmartlingExportFile culturePackage, List<SmartlingLocaleId> localeIds, string callbackUrl = default(string));
1919
}
2020
}

Entities/Plugins/TranslationManagement/Smartling/SmartlingExportFileProcessor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public SmartlingExportFileProcessor(
3636
_smartlingConfiguration = smartlingConfig;
3737
}
3838

39-
public T ProcessExportData<T>(string exportLookbackInDays, int exportMaxTablesPerFile, int maxRowsPerFile, CancellationToken ct, Database db)
39+
public T ProcessExportData<T>(string exportLookbackInDays, int exportMaxTablesPerFile, int maxRowsPerTable, CancellationToken ct, Database db)
4040
{
4141
Dictionary<string, ExportTable> exportTables = new Dictionary<string, ExportTable>();
4242
Dictionary<string, ExportTable> allTablesToExport = new Dictionary<string, ExportTable>();

Entities/Plugins/TranslationManagement/Smartling/SmartlingExportUtility.cs

Lines changed: 99 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using System.Linq;
99
using System.Threading;
1010
using System.Threading.Tasks;
11+
using Entities;
1112
using static Entities.Plugins.TranslationManagement.Smartling.SmartlingFileData;
1213

1314
namespace Entities.Plugins.TranslationManagement.Smartling
@@ -54,7 +55,7 @@ protected override async Task ProcessExport(CancellationToken ct, List<string> c
5455
{
5556
string packageId = Guid.NewGuid().ToString();
5657

57-
dtmData = _fileProcessor.ProcessExportData<SmartlingAppData>(ExportLookbackInDays, ExportMaxTablesPerFile, MaxRowsPerFile, ct, db);
58+
dtmData = _fileProcessor.ProcessExportData<SmartlingAppData>(ExportLookbackInDays, ExportMaxTablesPerFile, MaxRowsPerTable, ct, db);
5859

5960
if (dtmData.FileData != null && dtmData.FileData.Tables.Count > 0)
6061
{
@@ -112,60 +113,44 @@ public async Task BuildPackageAsync(SmartlingAppData appData, string packageId,
112113
}
113114
}
114115

115-
public Dictionary<string, SmartlingExportFile> BuildDtmFileDataCollection(SmartlingFileData dtmCultureData, int exportMaxTablesPerFile, int maxRowsPerFile)
116+
public static Dictionary<string, SmartlingExportFile> BuildDtmFileDataCollection(SmartlingFileData dtmCultureData, int exportMaxTablesPerFile, int maxRowsPerTable)
116117
{
117-
//A dictionary to hold all sub files per file
118-
Dictionary<string, SmartlingExportFile> subFiles = new Dictionary<string, SmartlingExportFile>();
119-
120-
//A dictionary to hold all sub data per file
121-
Dictionary<string, SmartlingFileData> subData = new Dictionary<string, SmartlingFileData>();
118+
if (dtmCultureData != null && dtmCultureData.Tables != null && dtmCultureData.Tables.Any())
119+
{
120+
//A dictionary to hold all sub files per file
121+
Dictionary<string, SmartlingExportFile> subFiles = new Dictionary<string, SmartlingExportFile>();
122122

123-
//first we need to divide the data based on the exportMaxTablesPerFile value and then the maxRowsPerFile value
124-
IEnumerable<IEnumerable<Table>> chunkTables = dtmCultureData?.Tables?.AsEnumerable().ToChunks(exportMaxTablesPerFile)
125-
.Select(rows => rows.ToList());
123+
//A dictionary to hold all row chunks per table file
124+
Dictionary<string, List<HashSet<Row>>> tabelRowChunks = new Dictionary<string, List<HashSet<Row>>>();
126125

127-
int tableListCount = 0;
128-
if ((bool)chunkTables?.Any())
129-
{
130-
foreach (IEnumerable<Table> tableList in chunkTables)
126+
int tableCount = 0;
127+
foreach (Table table in dtmCultureData.Tables)
131128
{
132-
SmartlingFileData subFile = new SmartlingFileData();
133-
subFile.smartling = dtmCultureData.smartling;
134-
subFile.GlobalizationMetaData = dtmCultureData.GlobalizationMetaData;
135-
subFile.Tables = new List<Table>();
136-
foreach (Table table in tableList)
137-
{
138-
IEnumerable<IEnumerable<Row>> chunkRows = table.Rows?.AsEnumerable().ToChunks(maxRowsPerFile)
139-
.Select(rows => rows.ToHashSet());
129+
//Get rows based on the max number of rows we're allowed per table
130+
List<HashSet<Row>> chunkRows = SplitRowList<Row>(table.Rows, maxRowsPerTable);
140131

141-
if (chunkRows != null)
132+
if (chunkRows != null)
133+
{
134+
foreach (IEnumerable<Row> chunk in chunkRows)
142135
{
143-
//create a new file for each chunk of rows
144-
foreach (IEnumerable<Row> chunk in chunkRows)
145-
{
136+
List<HashSet<Row>> rows = new List<HashSet<Row>>() { chunk as HashSet<Row> };
146137

147-
Table subTable = new Table()
148-
{
149-
PrimaryKeyName = table.PrimaryKeyName,
150-
BaseTable = table.BaseTable,
151-
FullBaseTableName = table.FullBaseTableName,
152-
LocalizedTable = table.LocalizedTable,
153-
FullLocalizedTableName = table.FullLocalizedTableName,
154-
TableSchema = table.TableSchema,
155-
SystemColumns = table.SystemColumns,
156-
SourceLanguageColumns = table.SourceLanguageColumns,
157-
TranslatedLanguageColumns = table.TranslatedLanguageColumns,
158-
159-
Rows = chunk as HashSet<Row>,
160-
};
161-
subFile.Tables.Add(subTable);
138+
if (!tabelRowChunks.TryGetValue(table.FullBaseTableName, out List<HashSet<Row>> _))
139+
{
140+
tabelRowChunks.Add(table.FullBaseTableName, rows);
141+
}
142+
else
143+
{
144+
tabelRowChunks[table.FullBaseTableName].AddRange(rows);
162145
}
163146
}
164147
}
165-
subData.Add(subFile.GlobalizationMetaData.PackageId + "_" + dtmCultureData.GlobalizationMetaData.Locale + "_" + tableListCount.ToString(), subFile);
166-
tableListCount++;
148+
tableCount++;
167149
}
168150

151+
//split data into sub data objects
152+
Dictionary<string, SmartlingFileData> subData = GetSubData(dtmCultureData, tabelRowChunks);
153+
169154
//now we need to create ExportFile objects for each sub data object
170155
if (subData?.Count > 0)
171156
{
@@ -175,27 +160,30 @@ public Dictionary<string, SmartlingExportFile> BuildDtmFileDataCollection(Smartl
175160
subFiles.Add(fileCollection.Key, AddFile(fileCollection.Key, fileCollection.Value, dtmCultureData.GlobalizationMetaData));
176161
}
177162
}
163+
164+
return subFiles;
178165
}
179166

180-
return subFiles;
167+
return new Dictionary<string, SmartlingExportFile>();
181168
}
182169

183-
public virtual void AddDtmPackage(ref Dictionary<string, SmartlingExportFile> dtmPackage, SmartlingFileData fileData, string packageId)
170+
public virtual void AddDtmPackage(ref Dictionary<string, SmartlingExportFile> exportPackage, SmartlingFileData fileData, string packageId)
184171
{
185172
try
186173
{
187-
Dictionary<string, SmartlingExportFile> subFiles = BuildDtmFileDataCollection(fileData, ExportMaxTablesPerFile, MaxRowsPerFile);
174+
Dictionary<string, SmartlingExportFile> subFiles = BuildDtmFileDataCollection(fileData, ExportMaxTablesPerFile, MaxRowsPerTable);
188175

189176
if (subFiles?.Count > 0)
190177
{
191178
foreach (KeyValuePair<string, SmartlingExportFile> subFile in subFiles)
192179
{
193-
dtmPackage.Add(subFile.Key, subFile.Value);
180+
exportPackage.Add(subFile.Key, subFile.Value);
194181
}
195182
}
196183
else
197184
{
198-
dtmPackage.Add(packageId, new SmartlingExportFile(fileData, fileData.GlobalizationMetaData));
185+
fileData.GlobalizationMetaData.LastFile = true;
186+
exportPackage.Add(packageId, new SmartlingExportFile(fileData, fileData.GlobalizationMetaData));
199187
}
200188
}
201189
catch (Exception ex)
@@ -212,5 +200,68 @@ public static SmartlingExportFile AddFile(string fileName, SmartlingFileData job
212200
exportFile.FileName = fileName + ".json";
213201
return exportFile;
214202
}
203+
204+
private static Dictionary<string, SmartlingFileData> GetSubData(SmartlingFileData dtmCultureData, Dictionary<string, List<HashSet<Row>>> tabelRowChunks)
205+
{
206+
// Find the entry with the largest number of HashSet<Row> in its value list
207+
var maxEntry = tabelRowChunks
208+
.OrderByDescending(kvp => kvp.Value?.Count ?? 0)
209+
.FirstOrDefault();
210+
211+
//we need to know how many files we will need to create for each table
212+
int totalFilesNeeded = maxEntry.Value?.Count ?? 0;
213+
214+
Dictionary<string, SmartlingFileData> subData = new Dictionary<string, SmartlingFileData>();
215+
216+
int fileCount = 0;
217+
218+
while (fileCount < totalFilesNeeded)
219+
{
220+
SmartlingFileData subDataFile = new SmartlingFileData();
221+
subDataFile.Tables = new List<Table>();
222+
subDataFile.smartling = dtmCultureData.smartling;
223+
subDataFile.GlobalizationMetaData = dtmCultureData.GlobalizationMetaData;
224+
string fileName = $"{dtmCultureData.GlobalizationMetaData.PackageId}_{fileCount}";
225+
226+
foreach (Table table in dtmCultureData.Tables)
227+
{
228+
var rowSet = tabelRowChunks.FirstOrDefault(l => l.Key == table.FullBaseTableName).Value[fileCount];
229+
if (rowSet != null && rowSet.Count > fileCount)
230+
{
231+
// Create a new table object for each chunk
232+
Table newTable = new Table()
233+
{
234+
Rows = rowSet,
235+
FullBaseTableName = table.FullBaseTableName,
236+
LocalizedTable = table.LocalizedTable,
237+
PrimaryKeyName = table.PrimaryKeyName,
238+
SystemColumns = table.SystemColumns,
239+
SourceLanguageColumns = table.SourceLanguageColumns,
240+
TranslatedLanguageColumns = table.TranslatedLanguageColumns
241+
};
242+
subDataFile.Tables.Add(newTable);
243+
}
244+
}
245+
subData.Add(fileName, subDataFile);
246+
fileCount++;
247+
}
248+
249+
return subData;
250+
}
251+
252+
private static List<HashSet<T>> SplitRowList<T>(HashSet<T> list, int chunkSize)
253+
{
254+
var chunks = new List<HashSet<T>>();
255+
if (list == null || chunkSize <= 0)
256+
return chunks;
257+
258+
var array = list.ToArray();
259+
for (int i = 0; i < array.Length; i += chunkSize)
260+
{
261+
var chunk = array.Skip(i).Take(chunkSize);
262+
chunks.Add(new HashSet<T>(chunk));
263+
}
264+
return chunks;
265+
}
215266
}
216267
}

0 commit comments

Comments
 (0)