diff --git a/src/VirtualClient/VirtualClient.Actions/HammerDB/HammerDBClientExecutor.cs b/src/VirtualClient/VirtualClient.Actions/HammerDB/HammerDBClientExecutor.cs index 2ef87939b7..46d7117903 100644 --- a/src/VirtualClient/VirtualClient.Actions/HammerDB/HammerDBClientExecutor.cs +++ b/src/VirtualClient/VirtualClient.Actions/HammerDB/HammerDBClientExecutor.cs @@ -171,22 +171,29 @@ private Task ExecuteWorkloadAsync(EventContext telemetryContext, CancellationTok { using (BackgroundOperations profiling = BackgroundOperations.BeginProfiling(this, cancellationToken)) { - string command = "python3"; - string script = $"{this.HammerDBPackagePath}/run-workload.py"; - - using (IProcessProxy process = await this.ExecuteCommandAsync( - command, - script + " " + this.hammerDBExecutionArguments, - this.HammerDBPackagePath, - telemetryContext, - cancellationToken)) + if (string.Equals(this.Action, "PopulateDatabase", StringComparison.OrdinalIgnoreCase)) { - if (!cancellationToken.IsCancellationRequested) + await this.PrepareSQLDatabase(telemetryContext, cancellationToken); + } + else + { + string command = "python3"; + string script = $"{this.HammerDBPackagePath}/run-workload.py"; + + using (IProcessProxy process = await this.ExecuteCommandAsync( + command, + script + " " + this.hammerDBExecutionArguments, + this.HammerDBPackagePath, + telemetryContext, + cancellationToken)) { - await this.LogProcessDetailsAsync(process, telemetryContext, "HammerDB", logToFile: true); - process.ThrowIfErrored(process.StandardError.ToString(), ErrorReason.WorkloadFailed); + if (!cancellationToken.IsCancellationRequested) + { + await this.LogProcessDetailsAsync(process, telemetryContext, "HammerDB", logToFile: true); + process.ThrowIfErrored(process.StandardError.ToString(), ErrorReason.WorkloadFailed); - this.CaptureMetrics(process, telemetryContext, cancellationToken); + this.CaptureMetrics(process, telemetryContext, cancellationToken); + } } } } diff --git a/src/VirtualClient/VirtualClient.Actions/HammerDB/HammerDBExecutor.cs b/src/VirtualClient/VirtualClient.Actions/HammerDB/HammerDBExecutor.cs index be86aa7046..9bff07051f 100644 --- a/src/VirtualClient/VirtualClient.Actions/HammerDB/HammerDBExecutor.cs +++ b/src/VirtualClient/VirtualClient.Actions/HammerDB/HammerDBExecutor.cs @@ -160,6 +160,18 @@ public string SQLServer } } + /// + /// The action to perform. + /// + public string Action + { + get + { + this.Parameters.TryGetValue(nameof(HammerDBClientExecutor.Action), out IConvertible action); + return action?.ToString(); + } + } + /// /// Client used to communicate with the hosted instance of the /// Virtual Client API at server side. @@ -217,21 +229,25 @@ await this.CheckDistroSupportAsync(cancellationToken) .ConfigureAwait(false); await HammerDBExecutor.OpenFirewallPortsAsync(this.Port, this.SystemManager.FirewallManager, cancellationToken); - - DependencyPath hammerDBPackage = await this.GetPlatformSpecificPackageAsync(this.PackageName, cancellationToken); - this.HammerDBPackagePath = hammerDBPackage.Path; - - await this.InitializeExecutablesAsync(telemetryContext, cancellationToken); - + this.InitializeApiClients(cancellationToken); - await this.Logger.LogMessageAsync($"{this.TypeName}.ConfigureHammerDBFile", telemetryContext.Clone(), async () => + // Only load HammerDB package for x64 executors. + if (this.CpuArchitecture == System.Runtime.InteropServices.Architecture.X64) { - if (!cancellationToken.IsCancellationRequested) + DependencyPath hammerDBPackage = await this.GetPlatformSpecificPackageAsync(this.PackageName, cancellationToken); + this.HammerDBPackagePath = hammerDBPackage.Path; + + await this.InitializeExecutablesAsync(telemetryContext, cancellationToken); + + await this.Logger.LogMessageAsync($"{this.TypeName}.ConfigureHammerDBFile", telemetryContext.Clone(), async () => { - await this.ConfigureCreateHammerDBFile(telemetryContext, cancellationToken); - } - }); + if (!cancellationToken.IsCancellationRequested) + { + await this.ConfigureCreateHammerDBFile(telemetryContext, cancellationToken); + } + }); + } if (this.IsMultiRoleLayout()) { @@ -240,7 +256,7 @@ await this.Logger.LogMessageAsync($"{this.TypeName}.ConfigureHammerDBFile", tele this.ThrowIfLayoutClientIPAddressNotFound(layoutIPAddress); this.ThrowIfRoleNotSupported(clientInstance.Role); - } + } } /// @@ -294,8 +310,11 @@ protected async Task InitializeExecutablesAsync(EventContext telemetryContext, C await this.stateManager.SaveStateAsync(nameof(HammerDBState), state, cancellationToken); } - - private async Task PrepareSQLDatabase(EventContext telemetryContext, CancellationToken cancellationToken) + + /// + /// Prepares the SQL database by executing the createDB TCL script. + /// + protected async Task PrepareSQLDatabase(EventContext telemetryContext, CancellationToken cancellationToken) { string command = "python3"; @@ -353,7 +372,16 @@ private static Task OpenFirewallPortsAsync(int port, IFirewallManager firewallMa private async Task CheckDistroSupportAsync(CancellationToken cancellationToken) { - if (this.CpuArchitecture == System.Runtime.InteropServices.Architecture.X64) + // Check architecture support based on executor type and role + // HammerDBServerExecutor in Server role: Supports both X64 and ARM64 (PostgreSQL server can run on both) + // All other scenarios: Supports only X64 (HammerDB client operations don't support ARM64) + bool isServerExecutorInServerRole = this.IsInRole(ClientRole.Server) && this.GetType() == typeof(HammerDBServerExecutor); + bool isX64 = this.CpuArchitecture == System.Runtime.InteropServices.Architecture.X64; + bool isArm64 = this.CpuArchitecture == System.Runtime.InteropServices.Architecture.Arm64; + + bool isArchitectureSupported = isX64 || (isServerExecutorInServerRole && isArm64); + + if (isArchitectureSupported) { if (this.Platform == PlatformID.Unix) { diff --git a/src/VirtualClient/VirtualClient.Dependencies/PostgreSQLServer/PostgreSQLServerConfiguration.cs b/src/VirtualClient/VirtualClient.Dependencies/PostgreSQLServer/PostgreSQLServerConfiguration.cs index cd00a1affe..91e9196003 100644 --- a/src/VirtualClient/VirtualClient.Dependencies/PostgreSQLServer/PostgreSQLServerConfiguration.cs +++ b/src/VirtualClient/VirtualClient.Dependencies/PostgreSQLServer/PostgreSQLServerConfiguration.cs @@ -124,7 +124,23 @@ public string SharedMemoryBuffer return sharedMemoryBuffer?.ToString(); } } + + /// + /// stripedisk mount point. + /// + public string StripeDiskMountPoint + { + get + { + if (this.Parameters.TryGetValue(nameof(this.StripeDiskMountPoint), out IConvertible stripediskmountpoint) && stripediskmountpoint != null) + { + return stripediskmountpoint.ToString(); + } + return string.Empty; + } + } + /// /// Retrieves the interface to interacting with the underlying system. /// @@ -180,9 +196,31 @@ private async Task ConfigurePostgreSQLServerAsync(EventContext telemetryContext, string serverIp = (this.GetLayoutClientInstances(ClientRole.Server, false) ?? Enumerable.Empty()) .FirstOrDefault()?.IPAddress ?? IPAddress.Loopback.ToString(); - + string arguments = $"{this.packageDirectory}/configure-server.py --dbName {this.DatabaseName} --serverIp {serverIp} --password {this.SuperUserPassword} --port {this.Port} --inMemory {this.SharedMemoryBuffer}"; + string innoDbDirs = string.Empty; + if (this.Parameters.ContainsKey(nameof(this.DiskFilter)) || !string.IsNullOrEmpty(this.StripeDiskMountPoint)) + { + innoDbDirs = this.Parameters.ContainsKey(nameof(this.DiskFilter)) ? await this.GetPostgreSQLInnodbDirectoriesAsync(cancellationToken) : string.Empty; + innoDbDirs = !string.IsNullOrEmpty(this.StripeDiskMountPoint) ? this.StripeDiskMountPoint : innoDbDirs; + + if (!string.IsNullOrEmpty(innoDbDirs)) + { + if (innoDbDirs.Split(';', StringSplitOptions.RemoveEmptyEntries).Length == 1) + { + string cleanDirectory = innoDbDirs.TrimEnd(';'); + arguments += $" --innodbDirectory {cleanDirectory}"; + } + else + { + throw new WorkloadException( + "Multiple InnoDB directories detected. Please specify a single directory for PostgreSQL configuration when using the DiskFilter parameter explicitly for PostgreSQLServerConfiguration.", + ErrorReason.InvalidProfileDefinition); + } + } + } + using (IProcessProxy process = await this.ExecuteCommandAsync( "python3", arguments, @@ -216,7 +254,7 @@ private async Task SetupPostgreSQLDatabaseAsync(EventContext telemetryContext, C } } } - + private async Task DistributePostgreSQLDatabaseAsync(EventContext telemetryContext, CancellationToken cancellationToken) { string innoDbDirs = await this.GetPostgreSQLInnodbDirectoriesAsync(cancellationToken); diff --git a/src/VirtualClient/VirtualClient.Main/profiles/PERF-POSTGRESQL-HAMMERDB-TPCC.json b/src/VirtualClient/VirtualClient.Main/profiles/PERF-POSTGRESQL-HAMMERDB-TPCC.json index 616dc6d4a8..40e1541aec 100644 --- a/src/VirtualClient/VirtualClient.Main/profiles/PERF-POSTGRESQL-HAMMERDB-TPCC.json +++ b/src/VirtualClient/VirtualClient.Main/profiles/PERF-POSTGRESQL-HAMMERDB-TPCC.json @@ -71,7 +71,7 @@ "Parameters": { "Scenario": "DownloadPostgreSQLPackage", "BlobContainer": "packages", - "BlobName": "postgresql.14.0.0.rev2.zip", + "BlobName": "postgresql.16.0.0.rev2.zip", "PackageName": "postgresql", "Extract": true } @@ -81,7 +81,7 @@ "Parameters": { "Scenario": "DownloadHammerDBPackage", "BlobContainer": "packages", - "BlobName": "hammerdb.4.7.0.rev1.zip", + "BlobName": "hammerdb.4.12.0.rev2.zip", "PackageName": "hammerdb", "Extract": true }