/// <summary> /// Moves the file from the incoming temporary folder and moves it to permanent storage. /// The file is automatically marked as recently accessed in order to prevent it from being evicted. /// </summary> /// <param name="id">The Id of the file</param> /// <param name="hash">The hash of the file</param> public void CompleteFile(Guid id, string hash) { string fileName = CacheFile.GetFileName(id, hash); string src = Path.Combine(this.incoming, fileName); string dest = CacheFile.GetFullFilePath(this.root, id, hash); if (!Directory.Exists(Path.GetDirectoryName(dest))) { Directory.CreateDirectory(Path.GetDirectoryName(dest)); } // For some reason the cache server is asking to overwrite the file, if (CacheFile.IsFileCached(this.root, id, hash)) { File.Delete(CacheFile.GetFullFilePath(this.root, id, hash)); } File.Move(src, dest); File.SetLastAccessTime(dest, DateTime.Now); FileInfo info = new FileInfo(dest); lock (this.cacheSizeBytesLock) { // Increment the cache size by adding a file this.cacheSizeBytes += (ulong)info.Length; int limit = Settings.Default.MaxCacheSizeMB * 1048576; // Check we haven't exceeded the cap if (this.cacheSizeBytes > (ulong)limit && !this.evictingCache) { // We've exceeded the cache cap, request a cleanup this.evictingCache = true; ThreadPool.QueueUserWorkItem(new WaitCallback(this.Evict)); } } // Store a hit on the ojbect File.SetLastAccessTime(dest, DateTime.Now); logger.Info(CultureInfo.CurrentCulture, "Moving {0} to permanent cache", fileName); }
/// <summary> /// Processes the get command /// </summary> /// <param name="stream">The stream to the client</param> private void ProcessGet(NetworkStream stream) { // Read ID Guid id = UnityCacheUtilities.ReadGuid(stream); string hash = UnityCacheUtilities.ReadHash(stream); if (!CacheFile.IsFileCached(this.fileManager.Root, id, hash)) { logger.Info("GET: Cache miss. {0} {1}", id, hash); // File is not cached // Send command it's not cached byte[] code = new byte[1]; code[0] = 45; stream.Write(code, 0, 1); // Send id and hash UnityCacheUtilities.SendIdAndHashOnStream(stream, id, hash); } else { logger.Info("GET: Cache hit. {0} {1}", id, hash); using (MemoryStream memoryStream = new MemoryStream(49)) { // File is cached, send the response byte[] code = new byte[1]; code[0] = 43; memoryStream.Write(code, 0, 1); // Send the file size in bytes ulong bytesToBeWritten = CacheFile.GetFileSizeBytes(this.fileManager.Root, id, hash); // Dumb off by 1 hack byte[] fileSizeBytes = UnityCacheUtilities.GetUlongAsAsciiBytes(bytesToBeWritten); memoryStream.Write(fileSizeBytes, 0, fileSizeBytes.Length); // Send id and hash UnityCacheUtilities.SendIdAndHashOnStream(memoryStream, id, hash); // Send the file bytes FileStream fileStream = this.fileManager.GetReadFileStream(id, hash); byte[] buffer = new byte[this.streamBlockSize]; // Workaround to get enough bytes into a single packet so the Unity client doesn't choke byte[] header = memoryStream.GetBuffer(); stream.Write(header, 0, header.Length); while (bytesToBeWritten > 0) { int byteCount = (bytesToBeWritten > (ulong)this.streamBlockSize) ? this.streamBlockSize : (int)bytesToBeWritten; fileStream.Read(buffer, 0, byteCount); bytesToBeWritten -= (ulong)byteCount; stream.Write(buffer, 0, byteCount); } fileStream.Close(); } } // Notify listeners a get was processed if (this.OnGetProcessed != null) { this.OnGetProcessed(this, new EventArgs()); } }