/// <summary> /// Computes a unique identifier for this bytecode instance. /// </summary> /// <returns>ObjectId.</returns> public ObjectId ComputeId() { var effectBytecode = this; // We should most of the time have stages, unless someone is calling this method on a new EffectBytecode if (effectBytecode.Stages != null) { effectBytecode = (EffectBytecode)MemberwiseClone(); effectBytecode.Stages = (ShaderBytecode[])effectBytecode.Stages.Clone(); // Because ShaderBytecode.Data can vary, we are calculating the bytecodeId only with the ShaderBytecode.Id. for (int i = 0; i < effectBytecode.Stages.Length; i++) { var newStage = effectBytecode.Stages[i].Clone(); effectBytecode.Stages[i] = newStage; newStage.Data = null; } } // Not optimized: Pre-calculate bytecodeId in order to avoid writing to same storage ObjectId newBytecodeId; var memStream = new MemoryStream(); using (var stream = new DigestStream(memStream)) { effectBytecode.WriteTo(stream); newBytecodeId = stream.CurrentHash; } return newBytecodeId; }
/// <inheritdoc/> public virtual ObjectId Write(ObjectId objectId, Stream dataStream, int length, bool forceWrite = false) { if (objectId == ObjectId.Empty) { // This should be avoided using (var digestStream = new DigestStream(Stream.Null)) { dataStream.CopyTo(digestStream); objectId = digestStream.CurrentHash; } dataStream.Seek(0, SeekOrigin.Begin); } string tmpFileName = vfsTempUrl + Guid.NewGuid() + ".tmp"; var url = BuildUrl(vfsRootUrl, objectId); if (!forceWrite && virtualFileProvider.FileExists(url)) { return(objectId); } using (var file = virtualFileProvider.OpenStream(tmpFileName, VirtualFileMode.Create, VirtualFileAccess.Write)) { // TODO: Fast case for NativeStream. However we still need a file implementation of NativeStream. var buffer = new byte[WriteBufferSize]; for (int offset = 0; offset < length; offset += WriteBufferSize) { int blockSize = length - offset; if (blockSize > WriteBufferSize) { blockSize = WriteBufferSize; } dataStream.Read(buffer, 0, blockSize); file.Write(buffer, 0, blockSize); } } MoveToDatabase(tmpFileName, objectId, forceWrite); return(objectId); }
/// <summary> /// Creates a in-memory binary blob as a <see cref="Blob"/> that will also be stored using the active <see cref="IOdbBackend"/>. /// Even if <see cref="Blob"/> is new (not in the ODB), memory will be copied. /// </summary> /// <param name="data">The data.</param> /// <param name="size">The size.</param> /// <returns>The <see cref="Blob"/> containing given data, with its reference count incremented.</returns> public Blob CreateBlob(IntPtr data, int size) { // Generate hash ObjectId objectId; var nativeMemoryStream = new NativeMemoryStream(data, size); using (var digestStream = new DigestStream(Stream.Null)) { nativeMemoryStream.CopyTo(digestStream); objectId = digestStream.CurrentHash; } lock (LoadedBlobs) { var blob = Lookup(objectId); // Blob doesn't exist yet, so let's create it and save it to ODB. if (blob == null) { // Let's go back to beginning of stream after previous hash nativeMemoryStream.Position = 0; // Create blob blob = new Blob(this, objectId, data, size); blob.AddReference(); // Write to disk backendWrite.Write(objectId, nativeMemoryStream, size, false); // Add blob to cache LoadedBlobs.Add(objectId, blob); } return(blob); } }
public unsafe void TestDigestStream() { string s1 = "abc"; string s2 = "abcdefghijklmnopqrstuvwxyz"; string s3 = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz123456789"; ObjectId xenkoHash; ObjectId dotNetHash; using (var ds = new DigestStream(new MemoryStream())) { ds.Write(Encoding.ASCII.GetBytes(s1), 0, s1.Length); xenkoHash = ds.CurrentHash; } using (var hashAlgorithm = new System.Security.Cryptography.SHA1Managed()) { dotNetHash = new ObjectId(hashAlgorithm.ComputeHash(Encoding.ASCII.GetBytes(s1))); } Assert.That(xenkoHash, Is.EqualTo(dotNetHash)); using (var ds = new DigestStream(new MemoryStream())) { ds.Write(Encoding.ASCII.GetBytes(s2), 0, s2.Length); xenkoHash = ds.CurrentHash; } using (var hashAlgorithm = new System.Security.Cryptography.SHA1Managed()) { dotNetHash = new ObjectId(hashAlgorithm.ComputeHash(Encoding.ASCII.GetBytes(s2))); } Assert.That(xenkoHash, Is.EqualTo(dotNetHash)); using (var ds = new DigestStream(new MemoryStream())) { ds.Write(Encoding.ASCII.GetBytes(s3), 0, s3.Length); xenkoHash = ds.CurrentHash; } using (var hashAlgorithm = new System.Security.Cryptography.SHA1Managed()) { dotNetHash = new ObjectId(hashAlgorithm.ComputeHash(Encoding.ASCII.GetBytes(s3))); } Assert.That(xenkoHash, Is.EqualTo(dotNetHash)); using (var ds = new DigestStream(new MemoryStream())) { ds.Write(Encoding.ASCII.GetBytes(s1), 0, s1.Length); ds.Write(Encoding.ASCII.GetBytes(s2), 0, s2.Length); ds.Write(Encoding.ASCII.GetBytes(s3), 0, s3.Length); xenkoHash = ds.CurrentHash; } using (var hashAlgorithm = new System.Security.Cryptography.SHA1Managed()) { dotNetHash = new ObjectId(hashAlgorithm.ComputeHash(Encoding.ASCII.GetBytes(s1 + s2 + s3))); } Assert.That(xenkoHash, Is.EqualTo(dotNetHash)); }
/// <summary> /// Computes the command hash. If an error occurecd, the hash is <see cref="ObjectId.Empty"/> /// </summary> /// <param name="prepareContext">The prepare context.</param> /// <returns>Hash of the command.</returns> internal ObjectId ComputeCommandHash(IPrepareContext prepareContext) { var stream = new DigestStream(Stream.Null); try { ComputeCommandHash(stream, prepareContext); return stream.CurrentHash; } catch (Exception ex) { prepareContext.Logger.Error("Unexpected error while computing the command hash for [{0}]. Reason: {1}", ex, this.GetType().Name, ex.Message); } return ObjectId.Empty; }
internal ObjectId ComputeCommandHash(IPrepareContext prepareContext) { var stream = new DigestStream(Stream.Null); ComputeCommandHash(stream, prepareContext); return stream.CurrentHash; }
/// <summary> /// Creates a in-memory binary blob as a <see cref="Blob"/> that will also be stored using the active <see cref="IOdbBackend"/>. /// Even if <see cref="Blob"/> is new (not in the ODB), memory will be copied. /// </summary> /// <param name="data">The data.</param> /// <param name="size">The size.</param> /// <returns>The <see cref="Blob"/> containing given data, with its reference count incremented.</returns> public Blob CreateBlob(IntPtr data, int size) { // Generate hash ObjectId objectId; var nativeMemoryStream = new NativeMemoryStream(data, size); using (var digestStream = new DigestStream(Stream.Null)) { nativeMemoryStream.CopyTo(digestStream); objectId = digestStream.CurrentHash; } lock (LoadedBlobs) { var blob = Lookup(objectId); // Blob doesn't exist yet, so let's create it and save it to ODB. if (blob == null) { // Let's go back to beginning of stream after previous hash nativeMemoryStream.Position = 0; // Create blob blob = new Blob(this, objectId, data, size); blob.AddReference(); // Write to disk backendWrite.Write(objectId, nativeMemoryStream, size, false); // Add blob to cache LoadedBlobs.Add(objectId, blob); } return blob; } }
/// <inheritdoc/> public virtual ObjectId Write(ObjectId objectId, Stream dataStream, int length, bool forceWrite = false) { if (objectId == ObjectId.Empty) { // This should be avoided using (var digestStream = new DigestStream(Stream.Null)) { dataStream.CopyTo(digestStream); objectId = digestStream.CurrentHash; } dataStream.Seek(0, SeekOrigin.Begin); } string tmpFileName = vfsTempUrl + Guid.NewGuid() + ".tmp"; var url = BuildUrl(vfsRootUrl, objectId); if (!forceWrite && virtualFileProvider.FileExists(url)) return objectId; using (var file = virtualFileProvider.OpenStream(tmpFileName, VirtualFileMode.Create, VirtualFileAccess.Write)) { // TODO: Fast case for NativeStream. However we still need a file implementation of NativeStream. var buffer = new byte[WriteBufferSize]; for (int offset = 0; offset < length; offset += WriteBufferSize) { int blockSize = length - offset; if (blockSize > WriteBufferSize) blockSize = WriteBufferSize; dataStream.Read(buffer, 0, blockSize); file.Write(buffer, 0, blockSize); } } MoveToDatabase(tmpFileName, objectId); return objectId; }