Guest User

Untitled

a guest
Jul 23rd, 2018
98
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.64 KB | None | 0 0
  1. using System;
  2. using System.Threading;
  3. using System.Collections.Generic;
  4.  
  5. namespace getScLog
  6. {
  7. //A simple class the represents a range between two integers
  8. class Range
  9. {
  10. public int start;
  11. public int end;
  12.  
  13. public Range (int start, int end)
  14. {
  15. this.start = start;
  16. this.end = end;
  17. }
  18.  
  19. //We assume end > start
  20. public int distance ()
  21. {
  22. return (this.end - this.start);
  23. }
  24.  
  25. //Just so we can output Range class easily
  26. public override String ToString ()
  27. {
  28. return String.Format ("Range({0},{1})", start, end);
  29. }
  30. }
  31.  
  32. //We use a class that calls our function one or more times
  33. //If first tries the full range and if it doesn't work bisects it into smaller ranges
  34. class Fetcher
  35. {
  36. //This is the function we call to do the work. If it fails by throwing a TimeOutException
  37. //the input range will be divided and the method will called twice.
  38. //First line is the type, next is an instance of that type;
  39. public delegate void Runner (Range r);
  40. Runner call;
  41.  
  42. //Number of calls to "call" we have made
  43. public int calls;
  44.  
  45.  
  46. //This holds the ranges we still need to fetch
  47. Queue<Range> tasks = new Queue<Range> ();
  48. //This is the minimum range we will call the delegate with (should be larger than 1)
  49. public int minRangeDistance = 3;
  50. public int retries = 0;
  51. public int maxDelay = 0;
  52. public int minDelay = 0;
  53. public int initialDelay = 0;
  54. //We keep track of any aborted ranges for logging purposes
  55. List<Range> failed = new List<Range> ();
  56. int delay;
  57.  
  58. public Fetcher (Runner call)
  59. {
  60. this.call = call;
  61. }
  62.  
  63. //To fetch something we simply add the range to the queue which will now hold a single element (the total range)
  64. //We then ask the fetcher to do the hard work
  65. public void run (int start, int end)
  66. {
  67. //TODO: Check min>=initial>=max,retries>=0,minRangeDistance>0
  68. failed = new List<Range> ();
  69. delay = initialDelay;
  70. Add (start, end);
  71. run ();
  72. while(failed.Count > 0 && retries>0){
  73. Console.WriteLine("Trying again");
  74. retries--;
  75. foreach(Range r in getFailed()){
  76. tasks.Enqueue(r);
  77. }
  78. run();
  79. }
  80. }
  81.  
  82. //We use this function for ensure we don't add to small ranges to the queue
  83. private void Add (int start, int end)
  84. {
  85. Range r = new Range (start, end);
  86. if (r.distance () < minRangeDistance) {
  87. updatefailed(r);
  88. } else {
  89. tasks.Enqueue (new Range (start, end));
  90. }
  91. }
  92.  
  93. //We have an aborted range. The way fetcher work they should actually come on order
  94. //so we merge the small ranges that fails and are adjacent
  95. private void updatefailed(Range r){
  96. if(failed.Count > 0 && failed[failed.Count-1].end == r.start)
  97. {
  98. failed[failed.Count-1].end = r.end;
  99. }
  100. else
  101. {
  102. failed.Add(r);
  103. }
  104. }
  105.  
  106. //This function does the scheduling of the calls
  107. private void run ()
  108. {
  109. //While we still have something to fetch
  110. while (tasks.Count > 0) {
  111. //Remove the range (in the first iteration the queue will now be empty)
  112. Range r = tasks.Dequeue ();
  113. if(calls != 0 && delay >= 0){
  114. Thread.Sleep(delay);
  115. }
  116. calls++;
  117. try {
  118. //We try calling the supplied function
  119. call (r);
  120. delay = limit(minDelay,delay - delay/4,maxDelay);
  121. } catch (TimeoutException) {
  122. //If this fails due to TimeOut, we (maybe) add to requests back to the queue
  123. //(The add function will not add too small a request)
  124. delay = limit(minDelay,delay<<1,maxDelay);
  125. int middle = (r.start + r.end) / 2;
  126. Add (r.start, middle);
  127. Add (middle, r.end);
  128. }
  129. }
  130. //At this point all ranges except the ones in failed will have been fetched
  131. }
  132.  
  133. public static int limit(int min, int a, int max){
  134. if(a<min)
  135. {
  136. return min;
  137. }
  138. if(a>max)
  139. {
  140. return max;
  141. }
  142. return a;
  143. }
  144.  
  145. public List<Range> getFailed ()
  146. {
  147. return failed;
  148. }
  149. }
  150.  
  151. //A simple test of our fetcher class
  152. class MainClass
  153. {
  154. public static void Main (string[] args)
  155. {
  156. //We define 3 variables we want to fetch (not related to the fetcher but for demonstration)
  157. List<String> vars = new List<String>() { "var_a", "var_b", "var_c", "var_d" };
  158.  
  159. //We add some reliabilities that is here the maximum value that can be fetched without guaranteed
  160. //failure.
  161. List<int> reliabilities = new List<int>() { 60, 1200, 90, 2000 };
  162.  
  163. //Used to simulate random failures
  164. Random random = new Random();
  165. for (int i=0;i<vars.Count;i++) {
  166. String s = vars[i];
  167. int reliability = reliabilities[i];
  168. //For each variable we define a function on how to fetch such a variable giving a range
  169. //Could be a call to a way more advanced system ;)
  170. Fetcher.Runner cb = delegate(Range r) {
  171. //Here we simulate a call to the service with a random failure chance
  172. //If the reliability is below 1000 we also add a non fecthable area to simulate permenent failures
  173. if (random.Next(reliability) < r.distance() || (reliability < 1000 && r.end > 800 && r.start < 900)) {
  174. //Lets writeout when we tell the Fetcher that it cant get the values
  175. Console.WriteLine ("Could not fetch " + s + " " + r);
  176. throw new TimeoutException ();
  177. }
  178. //...and when we can
  179. Console.WriteLine ("Got " + s + " " + r);
  180. };
  181. // We setup the fetcher
  182. Fetcher f = new Fetcher (cb);
  183. f.minRangeDistance = 7;
  184. f.retries = 1;
  185. f.maxDelay = 500;
  186. f.minDelay = 1;
  187. f.initialDelay = 1;
  188. // and ask it to get a range
  189. f.run (1, 1000);
  190. //Lastly we sum up the ranges that couldn't be fetched
  191. // Due to the merge of adjacent fails this should be a lot less than the "Could not fetch" messages
  192. Console.WriteLine ("Used {0} calls to fetch {1}",f.calls,s);
  193. foreach (Range r in f.getFailed ()) {
  194. Console.WriteLine ("Failed to get {0}", r);
  195. }
  196. }
  197. }
  198. }
  199. }
Add Comment
Please, Sign In to add comment