public override void PreCommand(ICommandContext commandContext) { base.PreCommand(commandContext); buildTransaction = MicrothreadLocalDatabases.CreateTransaction(commandContext.GetOutputObjectsGroups()); MicrothreadLocalDatabases.MountDatabase(buildTransaction); }
/// <summary> /// Load an asset to the preview. /// </summary> /// <typeparam name="TAssetType">The type of the asset to load</typeparam> /// <param name="url">The path to the asset to load</param> /// <param name="settings">The settings. If null, fallback to <see cref="ContentManagerLoaderSettings.Default" />.</param> /// <returns>The loaded asset</returns> public TAssetType LoadAsset <TAssetType>(string url, ContentManagerLoaderSettings settings = null) where TAssetType : class { TAssetType result = null; try { // This method can be invoked both from a script and from a regular task. In the second case, it will use the out-of-microthread database which need to be locked. // TODO: Ensure this method is always called from the preview game (it is not at least when a property is modified, currently), so we don't need to lock. Note: should be the case now, assume it is after GDC! if (Scheduler.CurrentMicroThread == null) { Monitor.Enter(AssetBuilderService.OutOfMicrothreadDatabaseLock); } MicrothreadLocalDatabases.MountDatabase(OutputObjects.Yield()); try { result = Game.Content.Load <TAssetType>(url, settings); } finally { if (Scheduler.CurrentMicroThread == null) { MicrothreadLocalDatabases.UnmountDatabase(); } } } catch (Exception e) { Builder.Logger.Error($"An exception was triggered when trying to load the entity [{url}] for the preview of asset item [{AssetItem.Location}].", e); } finally { if (Scheduler.CurrentMicroThread == null) { Monitor.Exit(AssetBuilderService.OutOfMicrothreadDatabaseLock); } } return(result); }
public async Task <IDisposable> MountInCurrentMicroThread() { if (isDisposed) { throw new ObjectDisposedException(nameof(GameStudioDatabase)); } if (Scheduler.CurrentMicroThread == null) { throw new InvalidOperationException("The database can only be mounted in a micro-thread."); } var lockObject = await databaseLock.LockAsync(); // Return immediately if the database was disposed when waiting for the lock if (isDisposed) { return(lockObject); } MicrothreadLocalDatabases.MountDatabase(database.Yield()); return(lockObject); }
private BuildResultCode BuildSlave() { // Mount build path ((FileSystemProvider)VirtualFileSystem.ApplicationData).ChangeBasePath(builderOptions.BuildDirectory); VirtualFileSystem.CreateDirectory(VirtualFileSystem.ApplicationDatabasePath); // Open WCF channel with master builder var namedPipeBinding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None) { SendTimeout = TimeSpan.FromSeconds(300.0), MaxReceivedMessageSize = int.MaxValue }; var processBuilderRemote = ChannelFactory <IProcessBuilderRemote> .CreateChannel(namedPipeBinding, new EndpointAddress(builderOptions.SlavePipe)); try { RegisterRemoteLogger(processBuilderRemote); // Make sure to laod all assemblies containing serializers // TODO: Review how costly it is to do so, and possibily find a way to restrict what needs to be loaded (i.e. only app plugins?) foreach (var assemblyLocation in processBuilderRemote.GetAssemblyContainerLoadedAssemblies()) { AssemblyContainer.Default.LoadAssemblyFromPath(assemblyLocation, builderOptions.Logger); } // Create scheduler var scheduler = new Scheduler(); var status = ResultStatus.NotProcessed; // Schedule command string buildPath = builderOptions.BuildDirectory; Builder.OpenObjectDatabase(buildPath, VirtualFileSystem.ApplicationDatabaseIndexName); var logger = builderOptions.Logger; MicroThread microthread = scheduler.Add(async() => { // Deserialize command and parameters Command command = processBuilderRemote.GetCommandToExecute(); // Run command var inputHashes = FileVersionTracker.GetDefault(); var builderContext = new BuilderContext(inputHashes, null); var commandContext = new RemoteCommandContext(processBuilderRemote, command, builderContext, logger); MicrothreadLocalDatabases.MountDatabase(commandContext.GetOutputObjectsGroups()); command.PreCommand(commandContext); status = await command.DoCommand(commandContext); command.PostCommand(commandContext, status); // Returns result to master builder processBuilderRemote.RegisterResult(commandContext.ResultEntry); }); while (true) { scheduler.Run(); // Exit loop if no more micro threads lock (scheduler.MicroThreads) { if (!scheduler.MicroThreads.Any()) { break; } } Thread.Sleep(0); } // Rethrow any exception that happened in microthread if (microthread.Exception != null) { builderOptions.Logger.Fatal(microthread.Exception.ToString()); return(BuildResultCode.BuildError); } if (status == ResultStatus.Successful || status == ResultStatus.NotTriggeredWasSuccessful) { return(BuildResultCode.Successful); } return(BuildResultCode.BuildError); } finally { // Close WCF channel // ReSharper disable SuspiciousTypeConversion.Global ((IClientChannel)processBuilderRemote).Close(); // ReSharper restore SuspiciousTypeConversion.Global } }
private BuildResultCode BuildSlave() { // Mount build path ((FileSystemProvider)VirtualFileSystem.ApplicationData).ChangeBasePath(builderOptions.BuildDirectory); VirtualFileSystem.CreateDirectory(VirtualFileSystem.ApplicationDatabasePath); // Open ServiceWire Client Channel using (var client = new NpClient <IProcessBuilderRemote>(new NpEndPoint(builderOptions.SlavePipe), new StrideServiceWireSerializer())) { RegisterRemoteLogger(client); // Make sure to laod all assemblies containing serializers // TODO: Review how costly it is to do so, and possibily find a way to restrict what needs to be loaded (i.e. only app plugins?) foreach (var assemblyLocation in client.Proxy.GetAssemblyContainerLoadedAssemblies()) { AssemblyContainer.Default.LoadAssemblyFromPath(assemblyLocation, builderOptions.Logger); } // Create scheduler var scheduler = new Scheduler(); var status = ResultStatus.NotProcessed; // Schedule command string buildPath = builderOptions.BuildDirectory; Builder.OpenObjectDatabase(buildPath, VirtualFileSystem.ApplicationDatabaseIndexName); var logger = builderOptions.Logger; MicroThread microthread = scheduler.Add(async() => { // Deserialize command and parameters Command command = client.Proxy.GetCommandToExecute(); // Run command var inputHashes = FileVersionTracker.GetDefault(); var builderContext = new BuilderContext(inputHashes, null); var commandContext = new RemoteCommandContext(client.Proxy, command, builderContext, logger); MicrothreadLocalDatabases.MountDatabase(commandContext.GetOutputObjectsGroups()); command.PreCommand(commandContext); status = await command.DoCommand(commandContext); command.PostCommand(commandContext, status); // Returns result to master builder client.Proxy.RegisterResult(commandContext.ResultEntry); }); while (true) { scheduler.Run(); // Exit loop if no more micro threads lock (scheduler.MicroThreads) { if (!scheduler.MicroThreads.Any()) { break; } } Thread.Sleep(0); } // Rethrow any exception that happened in microthread if (microthread.Exception != null) { builderOptions.Logger.Fatal(microthread.Exception.ToString()); return(BuildResultCode.BuildError); } if (status == ResultStatus.Successful || status == ResultStatus.NotTriggeredWasSuccessful) { return(BuildResultCode.Successful); } return(BuildResultCode.BuildError); } }
private BuildResultCode BuildSlave() { // Mount build path ((FileSystemProvider)VirtualFileSystem.ApplicationData).ChangeBasePath(builderOptions.BuildDirectory); PrepareDatabases(); VirtualFileSystem.CreateDirectory(VirtualFileSystem.ApplicationDatabasePath); // Open WCF channel with master builder var namedPipeBinding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None) { SendTimeout = TimeSpan.FromSeconds(300.0) }; var processBuilderRemote = ChannelFactory <IProcessBuilderRemote> .CreateChannel(namedPipeBinding, new EndpointAddress(builderOptions.SlavePipe)); try { RegisterRemoteLogger(processBuilderRemote); // Create scheduler var scheduler = new Scheduler(); var status = ResultStatus.NotProcessed; // Schedule command string buildPath = builderOptions.BuildDirectory; string buildProfile = builderOptions.BuildProfile; Builder.OpenObjectDatabase(buildPath, VirtualFileSystem.ApplicationDatabaseIndexName); var logger = builderOptions.Logger; MicroThread microthread = scheduler.Add(async() => { // Deserialize command and parameters Command command = processBuilderRemote.GetCommandToExecute(); BuildParameterCollection parameters = processBuilderRemote.GetBuildParameters(); // Run command var inputHashes = FileVersionTracker.GetDefault(); var builderContext = new BuilderContext(buildPath, buildProfile, inputHashes, parameters, 0, null); var commandContext = new RemoteCommandContext(processBuilderRemote, command, builderContext, logger); MicrothreadLocalDatabases.MountDatabase(commandContext.GetOutputObjectsGroups()); command.PreCommand(commandContext); status = await command.DoCommand(commandContext); command.PostCommand(commandContext, status); // Returns result to master builder processBuilderRemote.RegisterResult(commandContext.ResultEntry); }); while (true) { scheduler.Run(); // Exit loop if no more micro threads lock (scheduler.MicroThreads) { if (!scheduler.MicroThreads.Any()) { break; } } Thread.Sleep(0); } // Rethrow any exception that happened in microthread if (microthread.Exception != null) { builderOptions.Logger.Fatal(microthread.Exception.ToString()); return(BuildResultCode.BuildError); } if (status == ResultStatus.Successful || status == ResultStatus.NotTriggeredWasSuccessful) { return(BuildResultCode.Successful); } return(BuildResultCode.BuildError); } finally { // Close WCF channel // ReSharper disable SuspiciousTypeConversion.Global ((IClientChannel)processBuilderRemote).Close(); // ReSharper restore SuspiciousTypeConversion.Global } }