5
5
using System . Collections . Generic ;
6
6
using System . IO ;
7
7
using System . IO . MemoryMappedFiles ;
8
+ using System . Linq ;
8
9
using System . Runtime . InteropServices ;
10
+ using Microsoft . Azure . WebJobs . Script . Workers . Rpc ;
9
11
using Microsoft . Extensions . Logging ;
10
12
11
13
namespace Microsoft . Azure . WebJobs . Script . Workers . SharedMemoryDataTransfer
@@ -15,15 +17,22 @@ namespace Microsoft.Azure.WebJobs.Script.Workers.SharedMemoryDataTransfer
15
17
/// </summary>
16
18
public class MemoryMappedFileAccessorUnix : MemoryMappedFileAccessor
17
19
{
18
- public MemoryMappedFileAccessorUnix ( ILogger < MemoryMappedFileAccessor > logger ) : base ( logger )
20
+ private IEnvironment _environment ;
21
+
22
+ public MemoryMappedFileAccessorUnix ( ILogger < MemoryMappedFileAccessor > logger , IEnvironment environment ) : base ( logger )
19
23
{
20
24
ValidatePlatform ( new List < OSPlatform > ( )
21
25
{
22
26
OSPlatform . Linux ,
23
27
OSPlatform . OSX
24
28
} ) ;
29
+
30
+ _environment = environment ;
31
+ ValidDirectories = GetValidDirectories ( ) ;
25
32
}
26
33
34
+ internal List < string > ValidDirectories { get ; private set ; }
35
+
27
36
public override bool TryCreate ( string mapName , long size , out MemoryMappedFile mmf )
28
37
{
29
38
mmf = null ;
@@ -127,6 +136,74 @@ public override void Delete(string mapName, MemoryMappedFile mmf)
127
136
}
128
137
}
129
138
139
+ /// <summary>
140
+ /// Checks if a list of directories is specified in AppSettings to create <see cref="MemoryMappedFile"/>.
141
+ /// If one is specified, returns that list. Otherwise returns the default list.
142
+ /// </summary>
143
+ /// <returns>List of paths of directories where <see cref="MemoryMappedFile"/> are allowed to be created.</returns>
144
+ internal List < string > GetAllowedDirectories ( )
145
+ {
146
+ string envVal = _environment . GetEnvironmentVariable ( RpcWorkerConstants . FunctionsUnixSharedMemoryDirectories ) ;
147
+ if ( string . IsNullOrEmpty ( envVal ) )
148
+ {
149
+ return SharedMemoryConstants . TempDirs ;
150
+ }
151
+
152
+ return envVal . Split ( ',' ) . ToList ( ) ;
153
+ }
154
+
155
+ /// <summary>
156
+ /// From a list of allowed directories where <see cref="MemoryMappedFile"/> can be created, it will return
157
+ /// a list of those that are valid (i.e. exist, or have been successfully created).
158
+ /// </summary>
159
+ /// <returns>List of paths of directories where <see cref="MemoryMappedFile"/> can be created.</returns>
160
+ internal List < string > GetValidDirectories ( )
161
+ {
162
+ List < string > allowedDirectories = GetAllowedDirectories ( ) ;
163
+ List < string > validDirectories = new List < string > ( ) ;
164
+
165
+ foreach ( string directory in allowedDirectories )
166
+ {
167
+ string path = Path . Combine ( directory , SharedMemoryConstants . TempDirSuffix ) ;
168
+ if ( Directory . Exists ( path ) )
169
+ {
170
+ Logger . LogTrace ( "Found directory for shared memory usage: {Directory}" , path ) ;
171
+ try
172
+ {
173
+ // If the directory already exists (maybe from a previous run of the host) then clean it up and start afresh
174
+ // The previously created memory maps in that directory are not needed and we need to should clean up the memory
175
+ Directory . Delete ( path , recursive : true ) ;
176
+ Logger . LogTrace ( "Cleaned up existing directory for shared memory usage: {Directory}" , path ) ;
177
+ }
178
+ catch ( Exception exception )
179
+ {
180
+ Logger . LogWarning ( exception , "Cannot delete existing directory for shared memory usage: {Directory}" , path ) ;
181
+ }
182
+ }
183
+
184
+ try
185
+ {
186
+ DirectoryInfo info = Directory . CreateDirectory ( path ) ;
187
+ if ( info . Exists )
188
+ {
189
+ validDirectories . Add ( path ) ;
190
+ Logger . LogTrace ( "Created directory for shared memory usage: {Directory}" , path ) ;
191
+ }
192
+ else
193
+ {
194
+ Logger . LogWarning ( "Directory for shared memory usage does not exist: {Directory}" , path ) ;
195
+ }
196
+ }
197
+ catch ( Exception exception )
198
+ {
199
+ Logger . LogWarning ( exception , "Cannot create directory for shared memory usage: {Directory}" , path ) ;
200
+ }
201
+ }
202
+
203
+ Logger . LogDebug ( "Valid directories for shared memory usage: {Directories}" , string . Join ( "," , validDirectories ) ) ;
204
+ return validDirectories ;
205
+ }
206
+
130
207
/// <summary>
131
208
/// Get the path of the file to store a <see cref="MemoryMappedFile"/>.
132
209
/// We first try to mount it in memory-mounted directories (e.g. /dev/shm/).
@@ -136,15 +213,11 @@ public override void Delete(string mapName, MemoryMappedFile mmf)
136
213
/// <see cref="null"/> otherwise.</returns>
137
214
private string GetPath ( string mapName )
138
215
{
139
- // We escape the mapName to make it a valid file name
140
- // Python will use urllib.parse.quote_plus(mapName)
141
- string escapedMapName = Uri . EscapeDataString ( mapName ) ;
142
-
143
216
// Check if the file already exists
144
217
string filePath ;
145
- foreach ( string tempDir in SharedMemoryConstants . TempDirs )
218
+ foreach ( string tempDir in ValidDirectories )
146
219
{
147
- filePath = Path . Combine ( tempDir , SharedMemoryConstants . TempDirSuffix , escapedMapName ) ;
220
+ filePath = Path . Combine ( tempDir , mapName ) ;
148
221
if ( File . Exists ( filePath ) )
149
222
{
150
223
return filePath ;
@@ -162,14 +235,11 @@ private string GetPath(string mapName)
162
235
/// <returns>Created path.</returns>
163
236
private string CreatePath ( string mapName , long size )
164
237
{
165
- string escapedMapName = Uri . EscapeDataString ( mapName ) ;
166
-
167
238
// Create a new file
168
- string newTempDir = GetDirectory ( size ) ;
169
- if ( newTempDir != null )
239
+ string tempDir = GetDirectory ( size ) ;
240
+ if ( tempDir != null )
170
241
{
171
- DirectoryInfo newTempDirInfo = Directory . CreateDirectory ( newTempDir ) ;
172
- return Path . Combine ( newTempDirInfo . FullName , escapedMapName ) ;
242
+ return Path . Combine ( tempDir , mapName ) ;
173
243
}
174
244
else
175
245
{
@@ -187,7 +257,7 @@ private string CreatePath(string mapName, long size)
187
257
/// <see cref="SharedMemoryConstants.TempDirSuffix"/> is used.</returns>
188
258
private string GetDirectory ( long size )
189
259
{
190
- foreach ( string tempDir in SharedMemoryConstants . TempDirs )
260
+ foreach ( string tempDir in ValidDirectories )
191
261
{
192
262
try
193
263
{
@@ -197,7 +267,7 @@ private string GetDirectory(long size)
197
267
long minSize = size + SharedMemoryConstants . TempDirMinSize ;
198
268
if ( driveInfo . AvailableFreeSpace > minSize )
199
269
{
200
- return Path . Combine ( tempDir , SharedMemoryConstants . TempDirSuffix ) ;
270
+ return tempDir ;
201
271
}
202
272
}
203
273
}
0 commit comments