flok 0.0.38 → 0.0.39

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/app/drivers/chrome/src/dispatch.js +41 -6
  3. data/app/drivers/chrome/src/persist.js +1 -10
  4. data/app/kern/dispatch.js +17 -23
  5. data/app/kern/gen_id.js +8 -0
  6. data/app/kern/macro.rb +20 -18
  7. data/app/kern/pagers/pg_spec0.js +20 -0
  8. data/app/kern/services/vm.rb +176 -30
  9. data/docs/client_api.md +3 -1
  10. data/docs/compilation.md +1 -1
  11. data/docs/dispatch.md +91 -0
  12. data/docs/kernel_api.md +3 -2
  13. data/docs/messaging.md +6 -1
  14. data/docs/mod/persist.md +4 -3
  15. data/docs/project_layout.md +2 -2
  16. data/docs/services/vm.md +116 -41
  17. data/docs/services/vm/pagers.md +38 -46
  18. data/lib/flok.rb +1 -0
  19. data/lib/flok/build.rb +3 -4
  20. data/lib/flok/macro.rb +27 -0
  21. data/lib/flok/services_compiler.rb +12 -8
  22. data/lib/flok/user_compiler.rb +131 -4
  23. data/lib/flok/version.rb +1 -1
  24. data/spec/env/kern.rb +71 -0
  25. data/spec/etc/macro_spec.rb +3 -8
  26. data/spec/etc/service_compiler/service3.rb +27 -0
  27. data/spec/etc/services_compiler_spec.rb +35 -27
  28. data/spec/iface/driver/dispatch_spec.rb +20 -0
  29. data/spec/iface/driver/persist_spec.rb +9 -24
  30. data/spec/iface/kern/ping_spec.rb +3 -24
  31. data/spec/kern/assets/vm/config4.rb +12 -0
  32. data/spec/kern/assets/vm/controller10.rb +26 -0
  33. data/spec/kern/assets/vm/controller11.rb +33 -0
  34. data/spec/kern/assets/vm/controller12.rb +45 -0
  35. data/spec/kern/assets/vm/controller13.rb +40 -0
  36. data/spec/kern/assets/vm/controller14.rb +14 -0
  37. data/spec/kern/assets/vm/controller15.rb +15 -0
  38. data/spec/kern/assets/vm/controller16.rb +29 -0
  39. data/spec/kern/assets/vm/controller17.rb +30 -0
  40. data/spec/kern/assets/vm/controller18.rb +28 -0
  41. data/spec/kern/assets/vm/controller19.rb +14 -0
  42. data/spec/kern/assets/vm/controller19b.rb +15 -0
  43. data/spec/kern/assets/vm/controller20.rb +19 -0
  44. data/spec/kern/assets/vm/controller21.rb +40 -0
  45. data/spec/kern/assets/vm/controller7.rb +18 -0
  46. data/spec/kern/assets/vm/controller8.rb +38 -0
  47. data/spec/kern/assets/vm/controller8b.rb +18 -0
  48. data/spec/kern/assets/vm/controller9.rb +20 -0
  49. data/spec/kern/assets/vm/controller_exc_2watch.rb +15 -0
  50. data/spec/kern/assets/vm/controller_exc_ewatch.rb +14 -0
  51. data/spec/kern/assets/vm/macros/copy_page_c.rb +23 -0
  52. data/spec/kern/assets/vm/macros/entry_del_c.rb +18 -0
  53. data/spec/kern/assets/vm/macros/entry_insert_c.rb +21 -0
  54. data/spec/kern/assets/vm/macros/entry_mutable_c.rb +33 -0
  55. data/spec/kern/assets/vm/macros/new_page_c.rb +7 -0
  56. data/spec/kern/assets/vm/macros/new_page_c2.rb +7 -0
  57. data/spec/kern/assets/vm/macros/set_page_head_c.rb +18 -0
  58. data/spec/kern/assets/vm/macros/set_page_next_c.rb +18 -0
  59. data/spec/kern/controller_macro_spec.rb +186 -0
  60. data/spec/kern/dispatch_spec.rb +125 -0
  61. data/spec/kern/functions_spec.rb +15 -0
  62. data/spec/kern/vm_service_spec.rb +874 -173
  63. metadata +70 -5
  64. data/docs/scheduling.md +0 -46
  65. data/spec/kern/rest_service_spec.rb +0 -45
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 847b5b5b82356f175e5193de663c69487bc543fc
4
- data.tar.gz: 06b557dd275ee22398619033cc94b893eb815cc8
3
+ metadata.gz: 069696218ad132364486c4d0256e3f274f8e19e3
4
+ data.tar.gz: 4d2f67fe000dbeb7baf2077632ede49358f5dc6e
5
5
  SHA512:
6
- metadata.gz: 2dd662522a021063c44cfdbea4db37ea388f7d82f42108be93cd2b68507286b21650e524c9a2f99d2025781a375ae6d133383bb767e77cfa5af9642d37467f36
7
- data.tar.gz: eed43cf8edd7d656d0364770c73468658bff40759621629f3e127627327ab7c9f03a3d3bf4200c079a5293297216fac924efb35bd259bb474bd1e97c6687ce26
6
+ metadata.gz: 127c0e54aa11cf77024c208600cff1027350272b39d57f8abd28f6e6030a8765483f3a732cdb7cdc39d221ba0ead994228b811e4f0da87efec5d68b9506ab516
7
+ data.tar.gz: 8c2cd9a6c868e0ffbfc8359817cea534221ab0a8e623fc75f70c64e49233716a78ee68cc5e968624efb0e35041648d4d0281b9a5501b2c3fa501673361054ccb
@@ -7,6 +7,13 @@
7
7
  //Here is an example with two successive calls
8
8
  // [2, 'mul', 3, 4, 1, 'print', 'hello world']
9
9
  function if_dispatch(qq) {
10
+ if (qq[0] == 'i') {
11
+ qq.shift();
12
+ if_dispatch_call_int_end = true
13
+ } else {
14
+ if_dispatch_call_int_end = false
15
+ }
16
+
10
17
  //If debug socket is attached, forward events to it
11
18
  //and do not process the events
12
19
  <% if @mods.include? "debug" %>
@@ -22,13 +29,32 @@ function if_dispatch(qq) {
22
29
  //The very first thing is the queue type
23
30
  var queueType = q.shift();
24
31
 
25
- //Where there is still things left on the queue
26
- while (q.length > 0) {
27
- //Grab the first thing off the queue, this is the arg count
28
- var argc = q.shift();
32
+ //Main queue events are run synchronously on w.r.t to this thread of execution
33
+ //Asynchronous events are dispatched individually
34
+ if (queueType === 0) {
35
+ //Where there is still things left on the queue
36
+ while (q.length > 0) {
37
+ //Grab the first thing off the queue, this is the arg count
38
+ var argc = q.shift();
29
39
 
30
- //Grab the next thing and look that up in the function table. Pass args left
31
- this[q.shift()].apply(null, q.splice(0, argc));
40
+ //Grab the next thing and look that up in the function table. Pass args left
41
+ this[q.shift()].apply(null, q.splice(0, argc));
42
+ }
43
+ } else {
44
+ //Dispatch asynchronous queue events
45
+ while (q.length > 0) {
46
+ //Grab the next thing and look that up in the function table. Pass args left
47
+ function({
48
+ var argc = q.shift();
49
+ var q0 = q.shift();
50
+ var q1 = q.splice(0, argc);
51
+ async_call = function() {
52
+ this[q0].apply(null, q1);
53
+ }
54
+
55
+ setTimeout(async_call, 0);
56
+ })();
57
+ }
32
58
  }
33
59
  }
34
60
 
@@ -36,6 +62,12 @@ function if_dispatch(qq) {
36
62
  <% if @mods.include? "debug" %>
37
63
  }
38
64
  <% end %>
65
+
66
+
67
+ if (if_dispatch_call_int_end) {
68
+ if_dispatch_call_int_end = false;
69
+ int_dispatch([])
70
+ }
39
71
  }
40
72
 
41
73
  function ping() {
@@ -50,3 +82,6 @@ function ping2(arg1, arg2) {
50
82
  int_dispatch([1, "pong2", arg1])
51
83
  int_dispatch([2, "pong2", arg1, arg2])
52
84
  }
85
+
86
+ function ping_nothing() {
87
+ }
@@ -14,16 +14,7 @@ function if_per_del_ns(ns) {
14
14
  }
15
15
 
16
16
  function if_per_get(s, ns, key) {
17
- function async() {
18
- var _ns = store.namespace(ns);
19
- var res = _ns.get(key);
20
- int_dispatch([2, "int_per_get_res", s, res]);
21
- }
22
- setTimeout(async, 0);
23
- }
24
-
25
- function if_per_get_sync(s, ns, key) {
26
17
  var _ns = store.namespace(ns);
27
18
  var res = _ns.get(key);
28
- int_dispatch([2, "int_per_get_res", s, res]);
19
+ int_dispatch([2, "int_per_get_res", s, ns, res]);
29
20
  }
data/app/kern/dispatch.js CHANGED
@@ -30,6 +30,9 @@ function int_dispatch(q) {
30
30
  //Now push all of what we can back
31
31
  var dump = [];
32
32
 
33
+ //Add 'i' to start
34
+ var incomplete = false;
35
+
33
36
  //Send main queue
34
37
  if (main_q.length > 0) {
35
38
  var out = [0];
@@ -43,20 +46,21 @@ function int_dispatch(q) {
43
46
  if (net_q.length > 0 && net_q_rem > 0) {
44
47
  //Always pick the minimum between the amount remaining and the q length
45
48
  var n = net_q.length < net_q_rem ? net_q.length : net_q_rem;
49
+ if (n != net_q.length) { incomplete = true; }
46
50
 
47
51
  var out = [1];
48
52
  var piece = net_q.splice(0, n);
49
53
  for (var i = 0; i < piece.length; ++i) {
50
54
  out.push.apply(out, piece[i]);
51
55
  }
52
- dump.push(out);
53
56
 
54
- net_q_rem -= n;
57
+ dump.push(out);
55
58
  }
56
59
 
57
60
  if (disk_q.length > 0 && disk_q_rem > 0) {
58
61
  //Always pick the minimum between the amount remaining and the q length
59
62
  var n = disk_q.length < disk_q_rem ? disk_q.length : disk_q_rem;
63
+ if (n != disk_q.length) { incomplete = true; }
60
64
 
61
65
  var out = [2];
62
66
  var piece = disk_q.splice(0, n);
@@ -64,13 +68,12 @@ function int_dispatch(q) {
64
68
  out.push.apply(out, piece[i]);
65
69
  }
66
70
  dump.push(out);
67
-
68
- disk_q_rem -= n;
69
71
  }
70
72
 
71
73
  if (cpu_q.length > 0 && cpu_q_rem > 0) {
72
74
  //Always pick the minimum between the amount remaining and the q length
73
75
  var n = cpu_q.length < cpu_q_rem ? cpu_q.length : cpu_q_rem;
76
+ if (n != cpu_q.length) { incomplete = true; }
74
77
 
75
78
  var out = [3];
76
79
  var piece = cpu_q.splice(0, n);
@@ -78,13 +81,12 @@ function int_dispatch(q) {
78
81
  out.push.apply(out, piece[i]);
79
82
  }
80
83
  dump.push(out);
81
-
82
- cpu_q_rem -= n;
83
84
  }
84
85
 
85
86
  if (gpu_q.length > 0 && gpu_q_rem > 0) {
86
87
  //Always pick the minimum between the amount remaining and the q length
87
88
  var n = gpu_q.length < gpu_q_rem ? gpu_q.length : gpu_q_rem;
89
+ if (n != gpu_q.length) { incomplete = true; }
88
90
 
89
91
  var out = [4];
90
92
  var piece = gpu_q.splice(0, n);
@@ -92,19 +94,9 @@ function int_dispatch(q) {
92
94
  out.push.apply(out, piece[i]);
93
95
  }
94
96
  dump.push(out);
95
-
96
- gpu_q_rem -= n;
97
97
  }
98
98
 
99
- //Send async queue
100
- if (async_q.length > 0) {
101
- var out = [5];
102
- for (var i = 0; i < async_q.length; ++i) {
103
- out.push.apply(out, async_q[i]);
104
- }
105
- dump.push(out);
106
- async_q = [];
107
- }
99
+ if (incomplete) { dump.unshift("i"); }
108
100
 
109
101
  if (dump.length != 0) {
110
102
  if_dispatch(dump);
@@ -135,8 +127,6 @@ function ping3(arg1) {
135
127
  SEND("cpu", "pong3");
136
128
  } else if (arg1 == "gpu") {
137
129
  SEND("gpu", "pong3");
138
- } else if (arg1 == "async") {
139
- SEND("async", "pong3");
140
130
  }
141
131
  }
142
132
 
@@ -151,8 +141,6 @@ function ping4(arg1) {
151
141
  SEND("cpu", "pong4");
152
142
  } else if (arg1 == "gpu") {
153
143
  SEND("gpu", "pong4");
154
- } else if (arg1 == "async") {
155
- SEND("async", "pong4");
156
144
  }
157
145
  }
158
146
 
@@ -166,7 +154,6 @@ function ping4_int(arg1) {
166
154
  ++cpu_q_rem;
167
155
  } else if (arg1 == "gpu") {
168
156
  ++gpu_q_rem;
169
- } else if (arg1 == "async") {
170
157
  }
171
158
  }
172
159
 
@@ -176,7 +163,6 @@ net_q = [];
176
163
  disk_q = [];
177
164
  cpu_q = [];
178
165
  gpu_q = [];
179
- async_q = [];
180
166
 
181
167
  //Each queue has a max # of things that can be en-queued
182
168
  //These are decremented when the message is sent (not just queued)
@@ -185,3 +171,11 @@ net_q_rem = 5;
185
171
  disk_q_rem = 5;
186
172
  cpu_q_rem = 5;
187
173
  gpu_q_rem = 5;
174
+
175
+ <% if @debug %>
176
+ function spec_dispatch_q(queue, count) {
177
+ for (var i = 0; i < count; ++i) {
178
+ queue.push([0, "spec"]);
179
+ }
180
+ }
181
+ <% end %>
@@ -0,0 +1,8 @@
1
+ //Generate a random seed
2
+ gen_seed = Math.floor(Math.random() * 1000000000);
3
+ gen_seed_s = Math.floor(Math.random() * 1000000000);
4
+
5
+ function gen_id() {
6
+ gen_seed += 1;
7
+ return crc32(gen_seed, gen_seed_s).toString();
8
+ }
data/app/kern/macro.rb CHANGED
@@ -1,24 +1,26 @@
1
- #Process one js code file at a time
2
- def macro_process text
3
- out = StringIO.new
1
+ module Flok
2
+ #Process one js code file at a time
3
+ def self.macro_process text
4
+ out = StringIO.new
4
5
 
5
- text.split("\n").each do |l|
6
- #Send macro
7
- if l =~ /SEND/
8
- l.strip!
9
- l.gsub!(/SEND\(/, "")
10
- l.gsub! /\)$/, ""
11
- l.gsub! /\);$/, ""
12
- o = l.split(",").map{|e| e.strip}
6
+ text.split("\n").each do |l|
7
+ #Send macro
8
+ if l =~ /SEND/
9
+ l.strip!
10
+ l.gsub!(/SEND\(/, "")
11
+ l.gsub! /\)$/, ""
12
+ l.gsub! /\);$/, ""
13
+ o = l.split(",").map{|e| e.strip}
13
14
 
14
- queue_name = o.shift.gsub(/"/, "")
15
+ queue_name = o.shift.gsub(/"/, "")
15
16
 
16
- res = %{#{queue_name}_q.push([#{o.count-1}, #{o.join(", ")}])}
17
- out.puts res
18
- else
19
- out.puts l
17
+ res = %{#{queue_name}_q.push([#{o.count-1}, #{o.join(", ")}])}
18
+ out.puts res
19
+ else
20
+ out.puts l
21
+ end
20
22
  end
21
- end
22
23
 
23
- return out.string
24
+ return out.string
25
+ end
24
26
  end
@@ -0,0 +1,20 @@
1
+ <% if @debug %>
2
+ function pg_spec0_init(ns, options) {
3
+ pg_spec0_watchlist = [];
4
+ pg_spec0_unwatchlist = [];
5
+ pg_spec0_init_params = {ns: ns, options: options};
6
+ pg_spec0_ns = ns;
7
+ }
8
+
9
+ function pg_spec0_watch(id, page) {
10
+ pg_spec0_watchlist.push({id: id, page: page});
11
+ }
12
+
13
+ function pg_spec0_unwatch(id) {
14
+ pg_spec0_unwatchlist.push(id);
15
+ }
16
+
17
+ function pg_spec0_write(page) {
18
+ vm_cache_write(pg_spec0_ns, page);
19
+ }
20
+ <% end %>
@@ -7,31 +7,91 @@ service :vm do
7
7
  <% end %>
8
8
  };
9
9
 
10
+ vm_dirty = {
11
+ <% @options[:pagers].each do |p| %>
12
+ <%= p[:namespace] %>: {},
13
+ <% end %>
14
+ };
15
+
16
+ vm_bp_to_nmap = {};
17
+
10
18
  //Notification listeners, converts ns+key to an array of base pointers
11
19
  vm_notify_map = {};
12
20
 
13
21
  //Cache
14
- function vm_cache_write(ns, key, value) {
15
- vm_cache[ns][key] = value;
16
- }
22
+ function vm_cache_write(ns, page) {
23
+ var old = vm_cache[ns][page._id];
24
+ if (old && old._hash == page._hash) { return; }
25
+
26
+ vm_dirty[ns][page._id] = page;
27
+ vm_cache[ns][page._id] = page;
17
28
 
18
- //Notification of a change
19
- function vm_notify(ns, key) {
20
29
  var a = vm_notify_map[ns];
21
30
  if (a) {
22
- var b = a[key];
31
+ var b = a[page._id];
23
32
 
24
33
  if (b) {
25
34
  for (var i = 0; i < b.length; ++i) {
26
- <% @options[:pagers].each do |p| %>
27
- if (ns === "<%= p[:namespace] %>") {
28
- <%= p[:name] %>_read(ns, b[i], key);
29
- }
30
- <% end %>
35
+ int_event(b, "read_res", page);
31
36
  }
32
37
  }
33
38
  }
34
39
  }
40
+
41
+ function vm_rehash_page(page) {
42
+ var z = 0;
43
+
44
+ //head and next are optional
45
+ if (page._head) { var z = crc32(0, page._head) }
46
+ if (page._next) { z = crc32(z, page._next) }
47
+
48
+ z = crc32(z, page._id)
49
+
50
+ var e = page.entries;
51
+ for (var i = 0; i < e.length; ++i) {
52
+ z = crc32(z, e[i]._sig);
53
+ }
54
+
55
+ page._hash = z.toString();
56
+ }
57
+
58
+ function vm_pageout() {
59
+ <% @options[:pagers].each do |p| %>
60
+ //Get id_to_page mappings
61
+ var id_to_page = vm_dirty["<%= p[:namespace] %>"];
62
+ if (id_to_page) {
63
+ var ids = Object.keys(id_to_page);
64
+
65
+ //For each mapping, write the page
66
+ for (var i = 0; i < ids.length; ++i) {
67
+ var p = id_to_page[ids[i]];
68
+ SEND("main", "if_per_set", "<%= p[:namespace] %>", ids[i], p);
69
+ }
70
+ <% end %>
71
+ }
72
+
73
+ //Clear dirty list
74
+ vm_dirty = {
75
+ <% @options[:pagers].each do |p| %>
76
+ <%= p[:namespace] %>: {},
77
+ <% end %>
78
+ };
79
+ }
80
+
81
+ //Part of the persist module
82
+ //res is page
83
+ function int_per_get_res(s, ns, res) {
84
+ //If there is already a cached entry, a pager beat us to it
85
+ //ignore this for now because the pager should be more up to
86
+ //date
87
+ if (vm_cache[ns][res._id]) { return };
88
+
89
+ vm_cache_write(ns, res);
90
+ }
91
+
92
+ <% if @debug %>
93
+ vm_write_list = [];
94
+ <% end %>
35
95
  }
36
96
 
37
97
  on_wakeup %{
@@ -44,7 +104,7 @@ service :vm do
44
104
 
45
105
  //Call init functions
46
106
  <% @options[:pagers].each do |p| %>
47
- <%= p[:name] %>_init(<%= (p[:options] || {}).to_json %>);
107
+ <%= p[:name] %>_init("<%= p[:namespace] %>", <%= (p[:options] || {}).to_json %>);
48
108
  <% end %>
49
109
  }
50
110
 
@@ -55,6 +115,35 @@ service :vm do
55
115
  }
56
116
 
57
117
  on_disconnect %{
118
+ //We need to remove all the entries in vm_notify_map, but we only
119
+ //get an array of bp for each array in vm_notify_map[ns][key]...
120
+ //So we use the inverted lookup of vm_bp_to_nmap[bp][ns][key] to get a pointer
121
+ //to vm_notify_map[ns][key] and associated index. We then delete all the
122
+ //entries out of vm_notify_map
123
+
124
+ //Foreach namespace
125
+ var nss = Object.keys(vm_bp_to_nmap[bp]);
126
+ for (var i = 0; i < nss.length; ++i) {
127
+ //Namespace node
128
+ var nn = vm_bp_to_nmap[bp][nss[i]];
129
+
130
+ //Get all keys (which are ids)
131
+ var nnk = Object.keys(nn);
132
+
133
+ for (var x = 0; x < nnk.length; ++x) {
134
+ //Array contains [node (pointer to vm_notify_map[ns][key]), index] where index points to base pointer of this
135
+ //controller in the array
136
+ var arr = nn[nnk[i]][0]
137
+ var idx = nn[nnk[i]][1]
138
+
139
+ //Remove
140
+ arr.splice(idx, 1);
141
+ }
142
+
143
+ }
144
+
145
+ //Now we just clean up vm_bp_to_nmap because it's no longer used
146
+ delete vm_bp_to_nmap[bp];
58
147
  }
59
148
 
60
149
  on "read_sync", %{
@@ -76,27 +165,19 @@ service :vm do
76
165
  int_event(bp, "read_sync_res", res);
77
166
  }
78
167
 
79
- on "read", %{
168
+ on "write", %{
80
169
  <% raise "No pagers given in options for vm" unless @options[:pagers] %>
81
170
 
82
- var cres = vm_cache[params.ns][params.key];
83
- if (cres != undefined) {
84
- int_event(bp, "read_res", {key: params.key, value: cres});
85
- }
171
+ //We are going to fix the _hash on the page
172
+ vm_rehash_page(params.page);
86
173
 
87
- <% @options[:pagers].each do |p| %>
88
- if (params.ns === "<%= p[:namespace] %>") {
89
- <%= p[:name] %>_read(params.ns, bp, params.key);
90
- }
174
+ <% if @debug %>
175
+ vm_write_list.push(params.page);
91
176
  <% end %>
92
- }
93
-
94
- on "write", %{
95
- <% raise "No pagers given in options for vm" unless @options[:pagers] %>
96
177
 
97
178
  <% @options[:pagers].each do |p| %>
98
179
  if (params.ns === "<%= p[:namespace] %>") {
99
- <%= p[:name] %>_write(params.key, params.value);
180
+ <%= p[:name] %>_write(params.page);
100
181
  }
101
182
  <% end %>
102
183
  }
@@ -104,6 +185,9 @@ service :vm do
104
185
  on "watch", %{
105
186
  <% raise "No pagers given in options for vm" unless @options[:pagers] %>
106
187
 
188
+ //Cache entry
189
+ var cache_entry = vm_cache[params.ns][params.id];
190
+
107
191
  //Ensure map exists
108
192
  ////////////////////////////////////////////////
109
193
  var a = vm_notify_map[params.ns];
@@ -112,18 +196,57 @@ service :vm do
112
196
  vm_notify_map[params.ns] = a;
113
197
  }
114
198
 
115
- var b = a[params.key];
199
+ var b = a[params.id];
116
200
  if (!b) {
117
201
  b = [];
118
- a[params.key] = b;
202
+ a[params.id] = b;
119
203
  }
120
204
 
205
+ <% if @debug %>
206
+ var midx = vm_notify_map[params.ns][params.id].indexOf(bp)
207
+ if (midx != -1) {
208
+ throw "Multiple calls to watch for the ns: " + params.ns + " and id: " + params.id
209
+ }
210
+ <% end %>
121
211
  b.push(bp)
122
212
  ////////////////////////////////////////////////
123
213
 
214
+ //Add to vm_bp_to_nmap
215
+ ////////////////////////////////////////////////
216
+ //Construct
217
+ if (vm_bp_to_nmap[bp] === undefined) { vm_bp_to_nmap[bp] = {}; }
218
+ if (vm_bp_to_nmap[bp][params.ns] === undefined) { vm_bp_to_nmap[bp][params.ns] = {}; }
219
+
220
+ //Add reverse mapping, length-1 because it was just pushed
221
+ vm_bp_to_nmap[bp][params.ns][params.id] = [b, b.length-1];
222
+
223
+ //If cache exists, then signal controller *now* while we wait for the pager
224
+ if (cache_entry) {
225
+ int_event(bp, "read_res", cache_entry);
226
+ }
227
+
228
+ //Send a request now for disk read for sync
229
+ if (!cache_entry && params.sync) {
230
+ SEND("main", "if_per_get", "vm", params.ns, params.id);
231
+ }
232
+
233
+ //Do not signal pager if there is a watch request already in place
234
+ //as pager already knows; if it's equal to 1, this is the 'first'
235
+ //watch to go through as we have no info on it but just added it
236
+ if (vm_notify_map[params.ns][params.id].length > 1) { return; }
237
+
238
+ //While we're waiting for the pager try loading from disk, if this
239
+ //disk request is slower than the pager response, that's ok...
240
+ //the disk response will double check to see if the cache got set
241
+ //somewhere and not set it itself.
242
+ if (!cache_entry && !params.sync) {
243
+ SEND("disk", "if_per_get", "vm", params.ns, params.id);
244
+ }
245
+
246
+ //Now load the appropriate pager
124
247
  <% @options[:pagers].each do |p| %>
125
248
  if (params.ns === "<%= p[:namespace] %>") {
126
- <%= p[:name] %>_watch(params.ns, params.key);
249
+ <%= p[:name] %>_watch(params.id, cache_entry);
127
250
  }
128
251
  <% end %>
129
252
  }
@@ -131,11 +254,34 @@ service :vm do
131
254
  on "unwatch", %{
132
255
  <% raise "No pagers given in options for vm" unless @options[:pagers] %>
133
256
 
257
+ var midx = vm_notify_map[params.ns][params.id].indexOf(bp)
258
+ vm_notify_map[params.ns][params.id].splice(midx, 1);
259
+
260
+ delete vm_bp_to_nmap[bp][params.ns][params.id];
261
+
134
262
  <% @options[:pagers].each do |p| %>
135
263
  if (params.ns === "<%= p[:namespace] %>") {
136
- <%= p[:name] %>_unwatch(params.ns, params.key);
264
+ <%= p[:name] %>_unwatch(params.id);
137
265
  }
138
266
  <% end %>
139
267
  }
140
268
 
269
+ on "unwatch", %{
270
+ <% raise "No pagers given in options for vm" unless @options[:pagers] %>
271
+
272
+ var midx = vm_notify_map[params.ns][params.id].indexOf(bp)
273
+ vm_notify_map[params.ns][params.id].splice(midx, 1);
274
+
275
+ delete vm_bp_to_nmap[bp][params.ns][params.id];
276
+
277
+ <% @options[:pagers].each do |p| %>
278
+ if (params.ns === "<%= p[:namespace] %>") {
279
+ <%= p[:name] %>_unwatch(params.id);
280
+ }
281
+ <% end %>
282
+ }
283
+
284
+ every 20.seconds, %{
285
+ vm_pageout();
286
+ }
141
287
  end