public AmazonDriveSeekableStream(AmazonDrive Drive, FileMetadata_Info downitem) : base() { this.Drive = Drive; targetItem = downitem; FileSize = targetItem.OrignalLength ?? 0; if (FileSize <= 0) { return; } slots = new SlotMaster(Drive, downitem, cts.Token); _Position = 0; if (downitem.contentProperties?.size > ConfigAPI.FilenameChangeTrickSize && !Regex.IsMatch(downitem.name, "^[\x20-\x7e]*$")) { OrgFilename = downitem.name; Config.Log.LogOut("AmazonDriveSeekableStream : <BIG FILE> temporary filename change"); Config.Log.LogOut("AmazonDriveSeekableStream : orgnal name : " + OrgFilename); Drive.renameItem(downitem.id, ConfigAPI.temporaryFilename + downitem.id).Wait(); } lastslot = ((downitem.OrignalLength ?? 0) - 1) / AmazonDriveStreamConfig.slotsize; lockslot1 = AmazonDriveStreamConfig.lockslotfirstnum; lockslot2 = lastslot - AmazonDriveStreamConfig.lockslotlastnum; if (lockslot2 < lockslot1) { lockslot2 = lockslot1; } slots.CreateTask(0); slots.CreateTask(lockslot2); slots.CreateTask(lockslot1); slots.CreateTask(lockslot1 + AmazonDriveStreamConfig.preforwardnum); }
public SlotTask(AmazonDrive Drive, FileMetadata_Info targetItem, CancellationToken ct = default(CancellationToken)) { cts = CancellationTokenSource.CreateLinkedTokenSource(ct, Internal_cts.Token); this.Drive = Drive; this.targetItem = targetItem; lastslot = ((targetItem.OrignalLength ?? 0) - 1) / AmazonDriveStreamConfig.slotsize; }
public SlotMaster(AmazonDrive Drive, FileMetadata_Info downitem, CancellationToken ct = default(CancellationToken)) { cts = CancellationTokenSource.CreateLinkedTokenSource(cts_internal.Token, ct); this.Drive = Drive; targetItem = downitem; lastslot = ((downitem.OrignalLength ?? 0) - 1) / AmazonDriveStreamConfig.slotsize; lockslot1 = AmazonDriveStreamConfig.lockslotfirstnum; lockslot2 = lastslot - AmazonDriveStreamConfig.lockslotlastnum; if (lockslot2 < lockslot1) { lockslot2 = lockslot1; } int extraslot = 0; Task.Run(() => { foreach (var newitem in SlotBuffer.GetConsumingEnumerable(cts.Token)) { try { slot.GetOrAdd(newitem.Key, newitem.Value); while (slot.Count > AmazonDriveStreamConfig.slotbacklog + extraslot) { Task.Delay(100, cts.Token).Wait(cts.Token); } if (cts.Token.IsCancellationRequested) { return; } } catch { } } }, cts.Token); Task.Run(() => { while (!cts.Token.IsCancellationRequested) { try { const int slotnumc = AmazonDriveStreamConfig.slotbacklog; // slotが多すぎるのでいらないものから消す if (slot.Count > slotnumc) { var pos = slot .OrderByDescending(x => x.Value.Age) .OrderBy(x => x.Value.ReadAge) .First().Key; var s = StartLock; if (s != null) { pos = s.Value; } //Config.Log.LogOut(string.Format("AmazonDriveStream : Removing slots current pos {0}", pos)); var deleteitem = slot .Where(x => !(x.Key >= StartLock && x.Key <= EndLock)) .Where(x => x.Key > lockslot1 && x.Key < lockslot2); deleteitem = deleteitem .Where(x => x.Key <pos - AmazonDriveStreamConfig.slotkeepold || x.Key> pos + AmazonDriveStreamConfig.slotbacklog * 2) .OrderByDescending(x => x.Value.ReadAge) .Take(slot.Count - slotnumc).ToArray(); foreach (var item in deleteitem) { MemoryStreamSlot o; if (slot.TryRemove(item.Key, out o)) { //Config.Log.LogOut(string.Format("AmazonDriveStream : Remove slot {0} pos {1:#,0} len {2:#,0}", item.Key, o.Offset, o.Length)); if (!(item.Key >= StartLock && item.Key <= EndLock)) { o.Dispose(); } else { slot.GetOrAdd(item.Key, o); } } } extraslot = slot.Count - slotnumc; } // 終了したタスクを除去する if (Tasks.Any(x => x.Done)) { var deleteitem = Tasks.Where(x => x.Done).ToArray(); foreach (var item in deleteitem) { SlotTask o; if (Tasks.TryTake(out o)) { //Config.Log.LogOut(string.Format("AmazonDriveStream : Remove end Task slot {0}", o.ReadingSlotno)); o.Dispose(); } } } // 走りすぎているスレットを消す if (accesslog.Count() > 0) { var min_point = accesslog.OrderByDescending(x => x.Value).Take(1).Min(x => x.Key); var max_point = min_point + AmazonDriveStreamConfig.slotbacklog; min_point = Math.Max(min_point - AmazonDriveStreamConfig.slotnearby * 2, 0); max_point = Math.Min(max_point + AmazonDriveStreamConfig.slotnearby * 2, lastslot); //Config.Log.LogOut(string.Format("AmazonDriveStream : min_point {0}", min_point)); //Config.Log.LogOut(string.Format("AmazonDriveStream : max_point {0}", max_point)); if (min_point < lockslot2 && Tasks.Any(x => x.ReadingSlotno < min_point && x.ReadingSlotno > lockslot1)) { var deleteitem = Tasks.Where(x => x.ReadingSlotno <min_point && x.ReadingSlotno> lockslot1).ToList(); SlotTask o; while (deleteitem.Count > 0 && Tasks.TryTake(out o)) { if (deleteitem.Contains(o)) { //Config.Log.LogOut(string.Format("AmazonDriveStream : Remove1 Task slot {0} too far({1})", o.ReadingSlotno, min_point)); deleteitem.Remove(o); o.Dispose(); } else { Tasks.Add(o); } } } if (Tasks.Count == 1) { Tasks.First().leadThread = true; } else { foreach (var item in Tasks) { item.leadThread = false; } } if (max_point > lockslot1 && Tasks.Any(x => x.ReadingSlotno > max_point && x.ReadingSlotno < lockslot2)) { var deleteitem = Tasks.Where(x => x.ReadingSlotno > max_point && x.ReadingSlotno < lockslot2).ToList(); SlotTask o; while (deleteitem.Count > 0 && Tasks.TryTake(out o)) { if (deleteitem.Contains(o)) { if (o.leadThread) { //Config.Log.LogOut(string.Format("AmazonDriveStream : LeadThread Task slot {0} too far({1})", o.ReadingSlotno, min_point)); deleteitem.Remove(o); Tasks.Add(o); } else { //Config.Log.LogOut(string.Format("AmazonDriveStream : Remove2 Task slot {0} too far({1})", o.ReadingSlotno, min_point)); deleteitem.Remove(o); o.Dispose(); } } else { Tasks.Add(o); } } } } } catch { } //Config.Log.LogOut(string.Format("AmazonDriveStream : Tasks {0} slots {1}", Tasks.Count, slot.Count)); //Config.Log.LogOut(string.Format("AmazonDriveStream : slot {0}", string.Join(",",Tasks.Select(x=>x.ReadingSlotno.ToString())))); Task.Delay(500, cts.Token).Wait(cts.Token); } }, cts.Token); }