Skip to content

Commit

Permalink
feat: application package loading for local file handling (#187)
Browse files Browse the repository at this point in the history
  • Loading branch information
lemaitre-aneo authored Aug 9, 2023
2 parents 43dcc43 + 01aac00 commit 53d5bb3
Show file tree
Hide file tree
Showing 11 changed files with 573 additions and 360 deletions.
8 changes: 5 additions & 3 deletions Common/src/Common/AppsOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ namespace ArmoniK.DevelopmentKit.Common;
[MarkDownDoc]
public static class AppsOptions
{
public const string GridVolumesKey = "gridVolumes";
public const string GridAppVolumesKey = "target_app_path";
public const string GridDataVolumesKey = "target_data_path";
public const string GridVolumesKey = "gridVolumes";
public const string GridAppVolumesKey = "target_app_path";
public const string GridDataVolumesKey = "target_data_path";
public const string GridAssemblyPathKey = "ServiceAssemblyPath";
public const string GridZipVolumePath = "target_zip_path";
}
1 change: 1 addition & 0 deletions Common/src/Common/ArmoniK.DevelopmentKit.Common.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<OutputType>Library</OutputType>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<IsPackable>true</IsPackable>
<LangVersion>10</LangVersion>
</PropertyGroup>

<ItemGroup>
Expand Down
109 changes: 109 additions & 0 deletions Common/src/Common/Utils/FileSpinLock.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// This file is part of the ArmoniK project
//
// Copyright (C) ANEO, 2021-2023. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License")
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using System;
using System.IO;
using System.Text;
using System.Threading;

using JetBrains.Annotations;

namespace ArmoniK.DevelopmentKit.Common.Utils;

/// <summary>
/// Spin lock on a file
/// </summary>
[PublicAPI]
public sealed class FileSpinLock : IDisposable
{
private static readonly byte[] LockBytes = Encoding.ASCII.GetBytes("locked");

[CanBeNull]
private readonly FileStream fileStream_;

/// <summary>
/// Creates a spinlock on the file. Sets <see cref="HasLock" /> to true if it successfully locked the file, false
/// otherwise
/// </summary>
/// <param name="lockFile">File to lock</param>
/// <param name="deleteOnUnlock">Delete the lockfile when this object is disposed</param>
/// <param name="timeoutMs">Maximum time to wait for the lock to be acquired</param>
/// <param name="spinIntervalMs">Interval between lock tries</param>
public FileSpinLock(string lockFile,
bool deleteOnUnlock = true,
int timeoutMs = 30000,
int spinIntervalMs = 250)
{
HasLock = false;
var currentSpinTime = 0;
spinIntervalMs = Math.Min(spinIntervalMs,
timeoutMs);
do
{
try
{
fileStream_ ??= new FileStream(lockFile,
FileMode.OpenOrCreate,
FileAccess.ReadWrite,
FileShare.None,
1,
FileOptions.WriteThrough | (deleteOnUnlock
? FileOptions.DeleteOnClose
: FileOptions.None));
if (fileStream_.Seek(0,
SeekOrigin.End) == 0)
{
fileStream_.Write(LockBytes,
0,
LockBytes.Length);
fileStream_.Flush();
}

fileStream_.Lock(0,
LockBytes.Length);

HasLock = true;
}
catch (IOException)
{
Thread.Sleep(spinIntervalMs);
currentSpinTime += spinIntervalMs;
}
catch (UnauthorizedAccessException)
{
Thread.Sleep(spinIntervalMs);
currentSpinTime += spinIntervalMs;
}
} while (!HasLock && currentSpinTime < timeoutMs + spinIntervalMs);
}

/// <summary>
/// True if the file is locked by the current class, false otherwise
/// </summary>
public bool HasLock { get; }

/// <inheritdoc />
public void Dispose()
{
if (HasLock)
{
fileStream_?.Unlock(0,
LockBytes.Length);
}

fileStream_?.Dispose();
}
}
38 changes: 14 additions & 24 deletions Worker/src/Common/Archive/IArchiver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.

using ArmoniK.DevelopmentKit.Common;

namespace ArmoniK.DevelopmentKit.Worker.Common.Archive;

/// <summary>
Expand All @@ -26,31 +24,23 @@ public interface IArchiver
/// <summary>
/// Extracts an archive file
/// </summary>
/// <param name="fileAdapter">File adapter to fetch the file</param>
/// <param name="filename">File name</param>
/// <returns>Path to assembly file</returns>
public string ExtractArchive(IFileAdapter fileAdapter,
string filename);
/// <param name="packageId">Package Id</param>
/// <param name="overwrite">Overwrite the files if they have been already extracted</param>
/// <returns>Path to extracted package folder</returns>
public string ExtractArchive(string filename,
PackageId packageId,
bool overwrite = false);

/// <summary>
/// Checks if the archive has already been extracted
/// Checks if the archive has already been extracted. If the file is being extracted by another process, waits for its
/// completion to return an answer
/// </summary>
/// <param name="fileAdapter">File adapter to fetch the file</param>
/// <param name="fileName">File name</param>
/// <param name="waitForArchiver">Number of 2 seconds intervals to wait for the lock file to be </param>
/// <param name="packageId">Package Id</param>
/// <param name="waitExtractionTimeoutMs">If the file is being extracted by another process, wait until this timeout</param>
/// <param name="waitSpinIntervalMs">Interval between file checks while waiting for extraction</param>
/// <returns>True if the archive has already been extracted, false otherwise</returns>
public bool ArchiveAlreadyExtracted(IFileAdapter fileAdapter,
string fileName,
int waitForArchiver);

/// <summary>
/// Download the archive from the fileAdapter
/// </summary>
/// <param name="fileAdapter">File adapter to fetch the file</param>
/// <param name="filename">File name</param>
/// <param name="skipIfExists">If set to true, doesn't download if the file already exists</param>
/// <returns>Path to the download archive</returns>
public string DownloadArchive(IFileAdapter fileAdapter,
string filename,
bool skipIfExists);
public bool ArchiveAlreadyExtracted(PackageId packageId,
int waitExtractionTimeoutMs = 60000,
int waitSpinIntervalMs = 1000);
}
Loading

0 comments on commit 53d5bb3

Please sign in to comment.