flok 0.0.66 → 0.0.67
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.
- checksums.yaml +4 -4
- data/app/drivers/CHROME/src/persist.js +1 -1
- data/app/kern/services/vm.rb +67 -31
- data/docs/mod/persist.md +1 -1
- data/docs/services/vm.md +14 -40
- data/lib/flok/version.rb +1 -1
- data/spec/iface/driver/persist_spec.rb +13 -13
- data/spec/kern/assets/vm/controller19c.rb +1 -1
- data/spec/kern/assets/vm/controller19e.rb +2 -2
- data/spec/kern/assets/vm/controller19f.rb +6 -3
- data/spec/kern/assets/vm/controller19g.rb +3 -3
- data/spec/kern/assets/vm/controller19h.rb +23 -0
- data/spec/kern/assets/vm/controller8ws.rb +21 -0
- data/spec/kern/vm_service_spec.rb +68 -81
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 33ebc378b4d4226cb152de93d0d3c6ff42936bad
|
4
|
+
data.tar.gz: eb5bce9429dd9499b956d88b2400315fcf565299
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f85617167569178963488188a1eb824e656aa0dec2fc6c6d1b719d21df16a71c651688c8f643155ead9c30a56d5c86b2e093df3a33abf40e3d3fb791da70d209
|
7
|
+
data.tar.gz: 5e36c86d1cc67d367d3d052a18966b545cfb0277b4db601a9dcfa6db9b5bdc3bfd735989647f0d0b0df68fe0bbacda590bae6b51348922261cad7b7a64861c33
|
data/app/kern/services/vm.rb
CHANGED
@@ -15,8 +15,6 @@ service :vm do
|
|
15
15
|
|
16
16
|
vm_bp_to_nmap = {};
|
17
17
|
|
18
|
-
vm_read_sync_in_progress = [];
|
19
|
-
|
20
18
|
//Notification listeners, converts ns+key to an array of base pointers
|
21
19
|
vm_notify_map = {
|
22
20
|
<% @options[:pagers].each do |p| %>
|
@@ -24,6 +22,8 @@ service :vm do
|
|
24
22
|
<% end %>
|
25
23
|
};
|
26
24
|
|
25
|
+
vm_cache_write_sync_pending = {};
|
26
|
+
|
27
27
|
//Cache
|
28
28
|
function vm_cache_write(ns, page) {
|
29
29
|
<% if @debug %>
|
@@ -49,13 +49,41 @@ service :vm do
|
|
49
49
|
vm_dirty[ns][page._id] = page;
|
50
50
|
vm_cache[ns][page._id] = page;
|
51
51
|
|
52
|
+
//List of controllers to notify synchronously
|
53
|
+
var sync_waiting_controllers = vm_cache_write_sync_pending[page._id];
|
54
|
+
|
55
|
+
if (sync_waiting_controllers !== undefined) {
|
56
|
+
//Map that holds all controllers synchronously sent (used to avoid sending
|
57
|
+
//those controllers that are also on vm_notify_map a second message)
|
58
|
+
var sync_sent_map = {};
|
59
|
+
|
60
|
+
for (var i = 0; i < sync_waiting_controllers.length; ++i) {
|
61
|
+
var c = sync_waiting_controllers[i];
|
62
|
+
|
63
|
+
//Save so we don't send the same controller during the async part if the controller
|
64
|
+
//also happends to be part of vm_notify_map (it watched)
|
65
|
+
sync_sent_map[c] = true;
|
66
|
+
|
67
|
+
//Notify controller synchronously
|
68
|
+
int_event(c, "read_res", page);
|
69
|
+
}
|
70
|
+
}
|
71
|
+
|
52
72
|
//Try to lookup view controller(s) to notify
|
53
73
|
var nbp = vm_notify_map[ns][page._id];
|
54
74
|
if (nbp) {
|
55
75
|
for (var i = 0; i < nbp.length; ++i) {
|
56
|
-
|
76
|
+
var cbp = nbp[i];
|
77
|
+
//Only send if we didn't just send it above in the previous
|
78
|
+
//block synchronously
|
79
|
+
if (sync_sent_map[cbp] === undefined) {
|
80
|
+
int_event_defer(cbp, "read_res", page);
|
81
|
+
}
|
57
82
|
}
|
58
83
|
}
|
84
|
+
|
85
|
+
//Clear the sync_waiting_controllers
|
86
|
+
delete vm_cache_write_sync_pending[page._id];
|
59
87
|
}
|
60
88
|
|
61
89
|
function vm_pageout() {
|
@@ -82,23 +110,27 @@ service :vm do
|
|
82
110
|
|
83
111
|
//Part of the persist module
|
84
112
|
//res is page
|
85
|
-
function int_per_get_res(s, ns, res) {
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
113
|
+
function int_per_get_res(s, ns, id, res) {
|
114
|
+
if (res !== null) {
|
115
|
+
//Write out to the cache
|
116
|
+
vm_transaction_begin();
|
117
|
+
vm_cache_write(ns, res);
|
118
|
+
vm_transaction_end();
|
119
|
+
} else {
|
120
|
+
//Result was blank, signal all controllers that read synchronously
|
121
|
+
var sync_waiting_controllers = vm_cache_write_sync_pending[id];
|
122
|
+
if (sync_waiting_controllers !== undefined) {
|
123
|
+
for (var i = 0; i < sync_waiting_controllers.length; ++i) {
|
124
|
+
var c = sync_waiting_controllers[i];
|
125
|
+
|
126
|
+
//Notify controller synchronously
|
127
|
+
int_event(c, "read_res", {});
|
128
|
+
}
|
129
|
+
}
|
98
130
|
|
99
|
-
|
100
|
-
|
101
|
-
|
131
|
+
//Remove all controllers from notification list
|
132
|
+
delete vm_cache_write_sync_pending[id];
|
133
|
+
}
|
102
134
|
}
|
103
135
|
|
104
136
|
<% if @debug %>
|
@@ -561,8 +593,18 @@ service :vm do
|
|
561
593
|
}
|
562
594
|
|
563
595
|
//Send a request now for disk read for sync
|
564
|
-
if (!cache_entry
|
565
|
-
|
596
|
+
if (!cache_entry) {
|
597
|
+
if (params.sync !== undefined && params.sync === true) {
|
598
|
+
//Add ourselves to synchronous read list so the next disk read will
|
599
|
+
//send a synchronous event to us (and then clear). We will not get the
|
600
|
+
//normal asynhronous read. Additionally, we may also get a `{}` page indicating
|
601
|
+
//that the page is blank
|
602
|
+
vm_cache_write_sync_pending[params.id] = vm_cache_write_sync_pending[params.id] || [];
|
603
|
+
vm_cache_write_sync_pending[params.id].push(bp);
|
604
|
+
SEND("main", "if_per_get", "vm", params.ns, params.id);
|
605
|
+
} else {
|
606
|
+
SEND("disk", "if_per_get", "vm", params.ns, params.id);
|
607
|
+
}
|
566
608
|
}
|
567
609
|
|
568
610
|
//Do not signal pager if there is a watch request already in place
|
@@ -570,14 +612,6 @@ service :vm do
|
|
570
612
|
//watch to go through as we have no info on it but just added it
|
571
613
|
if (vm_notify_map[params.ns][params.id].length > 1) { return; }
|
572
614
|
|
573
|
-
//While we're waiting for the pager try loading from disk, if this
|
574
|
-
//disk request is slower than the pager response, that's ok...
|
575
|
-
//the disk response will double check to see if the cache got set
|
576
|
-
//somewhere and not set it itself.
|
577
|
-
if (!cache_entry && !params.sync) {
|
578
|
-
SEND("disk", "if_per_get", "vm", params.ns, params.id);
|
579
|
-
}
|
580
|
-
|
581
615
|
//Now load the appropriate pager
|
582
616
|
<% @options[:pagers].each do |p| %>
|
583
617
|
if (params.ns === "<%= p[:namespace] %>") {
|
@@ -599,9 +633,11 @@ service :vm do
|
|
599
633
|
|
600
634
|
var cache_entry = vm_cache[params.ns][params.id];
|
601
635
|
if (cache_entry !== undefined) {
|
602
|
-
int_event(bp, "
|
636
|
+
int_event(bp, "read_res", cache_entry);
|
603
637
|
} else {
|
604
|
-
|
638
|
+
//Set this controller as awaiting as synchronous response
|
639
|
+
vm_cache_write_sync_pending[params.id] = vm_cache_write_sync_pending[params.id] || [];
|
640
|
+
vm_cache_write_sync_pending[params.id].push(bp);
|
605
641
|
SEND("main", "if_per_get", "vm", params.ns, params.id);
|
606
642
|
}
|
607
643
|
}
|
data/docs/mod/persist.md
CHANGED
@@ -15,6 +15,6 @@ It is expected that the kernel should manage the write-back cache and that the d
|
|
15
15
|
it is convenient to do so.
|
16
16
|
|
17
17
|
###Kernel interrupts
|
18
|
-
`int_per_get_res(s, ns, res)` - A response retrieved from `if_per_get` that contains the session key and result dictionary. Currently,
|
18
|
+
`int_per_get_res(s, ns, id, res)` - A response retrieved from `if_per_get` that contains the session key and result dictionary. Currently,
|
19
19
|
the service `vm` owns this function; so session does not have an effect on the outcome; but the string `"vm"` should be used for now for any
|
20
20
|
session keys involving persist.
|
data/docs/services/vm.md
CHANGED
@@ -97,39 +97,17 @@ you will want to copy your pager into a seperate piece of code and rename it so
|
|
97
97
|
##Requests
|
98
98
|
|
99
99
|
###`watch`
|
100
|
-
This is how you **read a page** and request notifications for any updates to a page
|
101
|
-
```js
|
102
|
-
if (page is resident in memory from previous cache write)
|
103
|
-
send the caller a read_res event *now*
|
104
|
-
|
105
|
-
increment_page_ref()
|
106
|
-
|
107
|
-
//Synchronously request disk load from cache; this will block
|
108
|
-
//Even if we have a request in progress; the synchronous
|
109
|
-
//may pre-empt that event because the disk queue might be loaded;
|
110
|
-
//so we need to send this anyway
|
111
|
-
if (page is not redisent in memory and synchronous) {
|
112
|
-
try_sync_load_from_disk_and_update_cache()
|
113
|
-
}
|
114
|
-
|
115
|
-
//Only notify if this is the first reference, other controllers who attempt a watch will not signal the pager because the pager already knows
|
116
|
-
//about this page
|
117
|
-
if first_reference {
|
118
|
-
pager_watch()
|
119
|
-
}
|
120
|
-
|
121
|
-
//Again, only attempt this if the page is not requested by anyone else and is not synchronous (because we would have already tried). The pager will be notified in the meantime, if the disk
|
122
|
-
//comes after the pager notification; then the disk will not do anything.
|
123
|
-
if (page is not resident in memory && not_synchronous) {
|
124
|
-
//This is an asynchronous request
|
125
|
-
try_load_from_disk_and_update_cache()
|
126
|
-
}
|
127
|
-
```
|
100
|
+
This is how you **read a page** and **request notifications for any updates to a page**.
|
128
101
|
* Parameters
|
129
102
|
* `ns` - The namespace of the page, e.g. 'user'
|
130
103
|
* `id` - Watching the page that contains this in the `_id` field
|
131
|
-
* `sync (optional)` - If set to `true` then the cache read will be performed synchronously
|
132
|
-
|
104
|
+
* `sync (optional)` - If set to `true` then the cache read will be performed synchronously and if the cache misses, the disk will be read
|
105
|
+
synchronously. If the disk read fails, there will be no warning but this is an untested state and most likely, the next pager read will
|
106
|
+
dispatch asynchronously. This isn't awful but you should never set the `sync` flag to be true on data that you have not already cached at
|
107
|
+
some point. This is useful for profile loading, etc. so you don't have to delay on startup to display user name, etc. Multiple `watch`
|
108
|
+
requests dispatched with `sync` flag within the same frame will incur no performance penalty, they will be coalesced into one disk read.
|
109
|
+
Likewise, a `sync` watch request is perfectly acceptible to be called many times for a new controller needing the information. There is little
|
110
|
+
performance benefit in locally caching the data and many drawbacks like not getting updates of changes.
|
133
111
|
* Event Responses
|
134
112
|
* `read_res` - Whenever a change occurs to a page or the first read.
|
135
113
|
* Returns an immutable page in params
|
@@ -151,16 +129,15 @@ use the modification helpers. These modification helpers implement copy on write
|
|
151
129
|
* If in `@debug` mode, the variable `vm_write_list` contains an array dictionary of the last page passed to the pager (tail is latest).
|
152
130
|
|
153
131
|
###`read_sync`
|
154
|
-
Read from the disk synchronously, or memory if it exists, and return the value in `
|
132
|
+
Read from the disk synchronously, or memory if it exists, and return the value in `read_res`. This will not watch the page. Multiple read_syncs
|
155
133
|
in the same frame are allowed but discouraged as the order that pages are received back may not necessarily be the order they were synhronously
|
156
134
|
requested. This is because a cached page will be returned by the call stack while a synchronous read has to go through the event queue.
|
157
135
|
* Parameters
|
158
136
|
* `ns` - Namespace of the page
|
159
137
|
* `id` - id of the page
|
160
138
|
* Event Responses
|
161
|
-
* `
|
162
|
-
* `
|
163
|
-
* `page` - The page that was retrieved (or null if it dosen't exist)
|
139
|
+
* `read_res`
|
140
|
+
* `entire params` - The page that was retrieved (or null if it dosen't exist)
|
164
141
|
|
165
142
|
##Cache
|
166
143
|
See below with `vm_cache_write` for how to write to the cache. Each pager can choose whether or not to cache; some pagers may cache only reads while others will cache writes. Failure to write to the cache at all will cause `watch` to never trigger. Some pagers may use a trick where writes are allowed, and go directly to the cache but nowhere else. This is to allow things like *pending* transactions where you can locally fake data until a server response is received which will both wipe the fake write and insert the new one. Cache writes will trigger `watch`; if you write to cache with `vm_cache_write` with a page that has the same `_hash` as a page that already exists in cache, no `watch` events will be triggered. Additionally, calling `vm_cache_write` with a non-modified page will result in no performance penalty. `vm_cache_write` notifies controllers asynchronously and is not effected by the `watch` flag on controllers.
|
@@ -176,12 +153,9 @@ Pageout is embodied in the function named `vm_pageout()`. This will asynchronous
|
|
176
153
|
* `vm_notify_map` - The dictionary used to lookup what controllers need to be notified about changes. Stored in `vm_notify_map[ns][id]` which yields an array of controller base pointers.
|
177
154
|
* `vm_bp_to_nmap` - A dictionary that maps a `bp` key (usually from a controller) to a dictionary. This dictionary contains a mapping of `bp => ns => id` to an array that contains `[node, index]` where `node` is a reference to `vm_notify_map[ns][id]`. This inverted map must (a) provide a way for `unwatch` to quickly remove entries from itself and (b) provide a way for all entries in `vm_notify_map` to be removed when something (usually a controller) disconrnects.
|
178
155
|
must support `unwatch` removal which we only receive the `bp`, `ns`, and `key`.
|
179
|
-
* `
|
180
|
-
|
181
|
-
|
182
|
-
like a synchronous high priority deferred queue. The *frontmost* of the array is the lowest index, and the *backmost* is the highest index. In
|
183
|
-
javascript, this means that new requests are placed via `vm_read_sync_in_progress.unshift(new_bp)` and when requests are serviced, they are
|
184
|
-
serviced via the `var bp = vm_read_sync_in_progress.pop()`.
|
156
|
+
* `vm_cache_write_sync_pending` - A hash mapping page_ids to controllers awaiting synchronous responeses, e.g.
|
157
|
+
`vm_cache_write_sync_pending[page_id][0..N] := bp`. Usually set via the `watch` request
|
158
|
+
during a sync call for disk reads or the synchronous `read_sync` request. The format for each element in the array is `{"page_id": [bp1, bp2], ...}`
|
185
159
|
|
186
160
|
##Helper Methods
|
187
161
|
|
data/lib/flok/version.rb
CHANGED
@@ -19,7 +19,7 @@ RSpec.describe "iface:driver:persist" do
|
|
19
19
|
@pipe.readline_timeout
|
20
20
|
|
21
21
|
@pipe.puts [[0, 0, "ping"]].to_json;
|
22
|
-
expect(@pipe).to readline_and_equal_json_x_within_y_seconds([0, "pong"],
|
22
|
+
expect(@pipe).to readline_and_equal_json_x_within_y_seconds([0, "pong"], 8.seconds)
|
23
23
|
end
|
24
24
|
|
25
25
|
it "retuns null when calling get on a blank key" do
|
@@ -29,8 +29,8 @@ RSpec.describe "iface:driver:persist" do
|
|
29
29
|
@pipe.puts [[0, 3, "if_per_get", "session", "my_ns", key]].to_json
|
30
30
|
|
31
31
|
#Expect a response
|
32
|
-
res = [3, "int_per_get_res", "session", "my_ns", nil]
|
33
|
-
expect(@pipe).to readline_and_equal_json_x_within_y_seconds(res,
|
32
|
+
res = [3, "int_per_get_res", "session", "my_ns", key, nil]
|
33
|
+
expect(@pipe).to readline_and_equal_json_x_within_y_seconds(res, 7.seconds)
|
34
34
|
end
|
35
35
|
|
36
36
|
it "Can set a persist, and then get" do
|
@@ -43,8 +43,8 @@ RSpec.describe "iface:driver:persist" do
|
|
43
43
|
@pipe.puts [[0, 3, "if_per_get", "session", "my_ns", key]].to_json
|
44
44
|
|
45
45
|
#Expect a response
|
46
|
-
res = [3, "int_per_get_res", "session", "my_ns", value]
|
47
|
-
expect(@pipe).to readline_and_equal_json_x_within_y_seconds(res,
|
46
|
+
res = [3, "int_per_get_res", "session", "my_ns", key, value]
|
47
|
+
expect(@pipe).to readline_and_equal_json_x_within_y_seconds(res, 8.seconds)
|
48
48
|
end
|
49
49
|
|
50
50
|
it "Can set a persist, delete the key, and then get" do
|
@@ -58,8 +58,8 @@ RSpec.describe "iface:driver:persist" do
|
|
58
58
|
@pipe.puts [[0, 3, "if_per_get", "session", "my_ns", key]].to_json
|
59
59
|
|
60
60
|
#Expect a response
|
61
|
-
res = [3, "int_per_get_res", "session", "my_ns", nil]
|
62
|
-
expect(@pipe).to readline_and_equal_json_x_within_y_seconds(res,
|
61
|
+
res = [3, "int_per_get_res", "session", "my_ns", key, nil]
|
62
|
+
expect(@pipe).to readline_and_equal_json_x_within_y_seconds(res, 8.seconds)
|
63
63
|
end
|
64
64
|
|
65
65
|
it "Can set two persists, delete one key, and then get" do
|
@@ -77,12 +77,12 @@ RSpec.describe "iface:driver:persist" do
|
|
77
77
|
@pipe.puts [[0, 3, "if_per_get", "session", "my_ns", key2]].to_json
|
78
78
|
|
79
79
|
#Results for first key
|
80
|
-
res = [3, "int_per_get_res", "session", "my_ns", nil]
|
81
|
-
expect(@pipe).to readline_and_equal_json_x_within_y_seconds(res,
|
80
|
+
res = [3, "int_per_get_res", "session", "my_ns", key, nil]
|
81
|
+
expect(@pipe).to readline_and_equal_json_x_within_y_seconds(res, 8.seconds)
|
82
82
|
|
83
83
|
#Expect a response
|
84
|
-
res = [3, "int_per_get_res", "session", "my_ns", value2]
|
85
|
-
expect(@pipe).to readline_and_equal_json_x_within_y_seconds(res,
|
84
|
+
res = [3, "int_per_get_res", "session", "my_ns", key2, value2]
|
85
|
+
expect(@pipe).to readline_and_equal_json_x_within_y_seconds(res, 8.seconds)
|
86
86
|
end
|
87
87
|
|
88
88
|
it "Can set a persist, delete the key via ns, and then get" do
|
@@ -96,7 +96,7 @@ RSpec.describe "iface:driver:persist" do
|
|
96
96
|
@pipe.puts [[0, 3, "if_per_get", "session", "my_ns", key]].to_json
|
97
97
|
|
98
98
|
#Expect a response
|
99
|
-
res = [3, "int_per_get_res", "session", "my_ns", nil]
|
100
|
-
expect(@pipe).to readline_and_equal_json_x_within_y_seconds(res,
|
99
|
+
res = [3, "int_per_get_res", "session", "my_ns", key, nil]
|
100
|
+
expect(@pipe).to readline_and_equal_json_x_within_y_seconds(res, 8.seconds)
|
101
101
|
end
|
102
102
|
end
|
@@ -21,7 +21,7 @@ controller :my_controller do
|
|
21
21
|
Embed("my_other_controller", "content", {});
|
22
22
|
}
|
23
23
|
|
24
|
-
on "
|
24
|
+
on "read_res", %{
|
25
25
|
my_controller_read_sync_res = params;
|
26
26
|
}
|
27
27
|
end
|
@@ -44,7 +44,7 @@ controller :my_other_controller do
|
|
44
44
|
Request("vm", "read_sync", info);
|
45
45
|
}
|
46
46
|
|
47
|
-
on "
|
47
|
+
on "read_res", %{
|
48
48
|
my_other_controller_read_sync_res = params;
|
49
49
|
}
|
50
50
|
end
|
@@ -17,7 +17,7 @@ controller :controller0 do
|
|
17
17
|
Embed("controller2", "second", {});
|
18
18
|
}
|
19
19
|
|
20
|
-
on "
|
20
|
+
on "read_res", %{
|
21
21
|
controller0_read_sync_res = params;
|
22
22
|
}
|
23
23
|
end
|
@@ -40,10 +40,13 @@ controller :controller1 do
|
|
40
40
|
}
|
41
41
|
//get page A (again, read from cache)
|
42
42
|
Request("vm", "read_sync", info);
|
43
|
+
throw "shit";
|
43
44
|
}
|
44
45
|
|
45
|
-
on "
|
46
|
+
on modifyread_res", %{
|
46
47
|
controller1_read_sync_res = params;
|
48
|
+
|
49
|
+
expect()
|
47
50
|
}
|
48
51
|
end
|
49
52
|
end
|
@@ -68,7 +71,7 @@ controller :controller2 do
|
|
68
71
|
Request("vm", "read_sync", info);
|
69
72
|
}
|
70
73
|
|
71
|
-
on "
|
74
|
+
on "read_res", %{
|
72
75
|
controller2_read_sync_res = params;
|
73
76
|
}
|
74
77
|
end
|
@@ -17,7 +17,7 @@ controller :controller0 do
|
|
17
17
|
Embed("controller2", "second", {});
|
18
18
|
}
|
19
19
|
|
20
|
-
on "
|
20
|
+
on "read_res", %{
|
21
21
|
controller0_read_sync_res = params;
|
22
22
|
}
|
23
23
|
end
|
@@ -42,7 +42,7 @@ controller :controller1 do
|
|
42
42
|
Request("vm", "read_sync", info);
|
43
43
|
}
|
44
44
|
|
45
|
-
on "
|
45
|
+
on "read_res", %{
|
46
46
|
controller1_read_sync_res = params;
|
47
47
|
}
|
48
48
|
end
|
@@ -68,7 +68,7 @@ controller :controller2 do
|
|
68
68
|
Request("vm", "read_sync", info);
|
69
69
|
}
|
70
70
|
|
71
|
-
on "
|
71
|
+
on "read_res", %{
|
72
72
|
controller2_read_sync_res = params;
|
73
73
|
}
|
74
74
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
controller :my_controller do
|
2
|
+
services :vm
|
3
|
+
|
4
|
+
on_entry %{
|
5
|
+
read_sync_res_params = [];
|
6
|
+
}
|
7
|
+
|
8
|
+
action :my_action do
|
9
|
+
on_entry %{
|
10
|
+
var info = {
|
11
|
+
ns: "spec",
|
12
|
+
id: "test"
|
13
|
+
}
|
14
|
+
|
15
|
+
Request("vm", "read_sync", info);
|
16
|
+
}
|
17
|
+
|
18
|
+
on "read_res", %{
|
19
|
+
read_sync_res_params.push(params);
|
20
|
+
}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
@@ -0,0 +1,21 @@
|
|
1
|
+
controller :my_controller do
|
2
|
+
spots "content"
|
3
|
+
services :vm
|
4
|
+
|
5
|
+
action :my_action do
|
6
|
+
on_entry %{
|
7
|
+
page0 = {
|
8
|
+
ns: "spec",
|
9
|
+
id: "my_key",
|
10
|
+
sync: true
|
11
|
+
};
|
12
|
+
|
13
|
+
Request("vm", "watch", page0);
|
14
|
+
}
|
15
|
+
|
16
|
+
on "read_res", %{
|
17
|
+
read_res_params = params;
|
18
|
+
}
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
@@ -671,8 +671,8 @@ RSpec.describe "kern:vm_service" do
|
|
671
671
|
@driver.ignore_up_to "if_per_get", 0
|
672
672
|
@driver.mexpect("if_per_get", ["vm", "spec", "test"], 0)
|
673
673
|
|
674
|
-
@driver.int "int_per_get_res", ["vm", "spec", {
|
675
|
-
"_id" => "
|
674
|
+
@driver.int "int_per_get_res", ["vm", "spec", "test", {
|
675
|
+
"_id" => "test",
|
676
676
|
"_hash" => nil,
|
677
677
|
"_next" => nil,
|
678
678
|
"entries" => [],
|
@@ -680,24 +680,48 @@ RSpec.describe "kern:vm_service" do
|
|
680
680
|
|
681
681
|
@driver.mexpect("if_per_get", ["vm", "spec", "test2"], 0)
|
682
682
|
|
683
|
-
@driver.int "int_per_get_res", ["vm", "spec", {
|
684
|
-
"_id" => "
|
683
|
+
@driver.int "int_per_get_res", ["vm", "spec", "test2", {
|
684
|
+
"_id" => "test2",
|
685
685
|
"_hash" => nil,
|
686
686
|
"_next" => nil,
|
687
687
|
"entries" => [],
|
688
688
|
}]
|
689
689
|
|
690
690
|
dump = ctx.evald %{
|
691
|
-
dump.vm_read_sync_in_progress = vm_read_sync_in_progress;
|
692
691
|
dump.read_sync_res_params = read_sync_res_params;
|
693
692
|
}
|
694
693
|
|
695
|
-
expect(dump["vm_read_sync_in_progress"]).to eq([])
|
696
694
|
expect(dump["read_sync_res_params"].length).to eq(2)
|
697
|
-
expect(dump["read_sync_res_params"][0]["
|
698
|
-
expect(dump["read_sync_res_params"][
|
699
|
-
|
700
|
-
|
695
|
+
expect(dump["read_sync_res_params"][0]["_id"]).to eq("test")
|
696
|
+
expect(dump["read_sync_res_params"][1]["_id"]).to eq("test2")
|
697
|
+
end
|
698
|
+
|
699
|
+
it "Does send a read request from disk cache when synchronously reading a key for the first time via read_sync, and returns a blank hash if the page does not exist" do
|
700
|
+
ctx = flok_new_user File.read('./spec/kern/assets/vm/controller19h.rb'), File.read("./spec/kern/assets/vm/config4.rb")
|
701
|
+
|
702
|
+
ctx.eval %{
|
703
|
+
base = _embed("my_controller", 1, {}, null);
|
704
|
+
|
705
|
+
//Call pageout *now*
|
706
|
+
vm_pageout();
|
707
|
+
|
708
|
+
//Drain queue
|
709
|
+
int_dispatch([]);
|
710
|
+
}
|
711
|
+
|
712
|
+
@driver.ignore_up_to "if_per_get", 0
|
713
|
+
@driver.mexpect("if_per_get", ["vm", "spec", "test"], 0)
|
714
|
+
|
715
|
+
#Send back blank result (Send two to make sure we only get one result back)
|
716
|
+
@driver.int "int_per_get_res", ["vm", "spec", "test", nil]
|
717
|
+
@driver.int "int_per_get_res", ["vm", "spec", "test", nil]
|
718
|
+
|
719
|
+
dump = ctx.evald %{
|
720
|
+
dump.read_sync_res_params = read_sync_res_params;
|
721
|
+
}
|
722
|
+
|
723
|
+
expect(dump["read_sync_res_params"].length).to eq(1)
|
724
|
+
expect(dump["read_sync_res_params"][0]).to eq({})
|
701
725
|
end
|
702
726
|
|
703
727
|
it "Calling read_sync on an entry that already exists in cache will not trigger a disk read" do
|
@@ -718,7 +742,7 @@ RSpec.describe "kern:vm_service" do
|
|
718
742
|
@driver.mexpect("if_per_get", ["vm", "spec", "test"], 0)
|
719
743
|
|
720
744
|
#Send the disk read response back controller19d:14
|
721
|
-
@driver.int "int_per_get_res", ["vm", "spec", {
|
745
|
+
@driver.int "int_per_get_res", ["vm", "spec", "test", {
|
722
746
|
"_id" => "test",
|
723
747
|
"_hash" => nil,
|
724
748
|
"_next" => nil,
|
@@ -754,7 +778,7 @@ RSpec.describe "kern:vm_service" do
|
|
754
778
|
@driver.mexpect("if_per_get", ["vm", "spec", "test2"], 0)
|
755
779
|
|
756
780
|
#Send the disk read response back for the first controller (my_controller)
|
757
|
-
@driver.int "int_per_get_res", ["vm", "spec", {
|
781
|
+
@driver.int "int_per_get_res", ["vm", "spec", "test1", {
|
758
782
|
"_id" => "test1",
|
759
783
|
"_hash" => nil,
|
760
784
|
"_next" => nil,
|
@@ -762,7 +786,7 @@ RSpec.describe "kern:vm_service" do
|
|
762
786
|
}]
|
763
787
|
|
764
788
|
#Send the disk read response back for the second controller (my_other_controller)
|
765
|
-
@driver.int "int_per_get_res", ["vm", "spec", {
|
789
|
+
@driver.int "int_per_get_res", ["vm", "spec", "test2", {
|
766
790
|
"_id" => "test2",
|
767
791
|
"_hash" => nil,
|
768
792
|
"_next" => nil,
|
@@ -775,8 +799,8 @@ RSpec.describe "kern:vm_service" do
|
|
775
799
|
dump.my_other_controller_read_sync_res = my_other_controller_read_sync_res;
|
776
800
|
}
|
777
801
|
|
778
|
-
expect(dump["my_controller_read_sync_res"]["
|
779
|
-
expect(dump["my_other_controller_read_sync_res"]["
|
802
|
+
expect(dump["my_controller_read_sync_res"]["_id"]).to eq("test1")
|
803
|
+
expect(dump["my_other_controller_read_sync_res"]["_id"]).to eq("test2")
|
780
804
|
end
|
781
805
|
|
782
806
|
it "Calling read_sync on frame0 for page 'A' on controller0 and then on frame1 for page 'A' on controller1 and page 'B' on controller2 will result in all controllers receiving the correct pages" do
|
@@ -796,7 +820,7 @@ RSpec.describe "kern:vm_service" do
|
|
796
820
|
@driver.mexpect("if_per_get", ["vm", "spec", "A"], 0)
|
797
821
|
|
798
822
|
#Send the disk read response back for controller0 pageA
|
799
|
-
@driver.int "int_per_get_res", ["vm", "spec", {
|
823
|
+
@driver.int "int_per_get_res", ["vm", "spec", "A", {
|
800
824
|
"_id" => "A",
|
801
825
|
"_hash" => nil,
|
802
826
|
"_next" => nil,
|
@@ -812,7 +836,7 @@ RSpec.describe "kern:vm_service" do
|
|
812
836
|
@driver.mexpect("if_per_get", ["vm", "spec", "B"], 0)
|
813
837
|
|
814
838
|
#Send the disk read response back for frame1 'B' for controller2
|
815
|
-
@driver.int "int_per_get_res", ["vm", "spec", {
|
839
|
+
@driver.int "int_per_get_res", ["vm", "spec", "B", {
|
816
840
|
"_id" => "B",
|
817
841
|
"_hash" => nil,
|
818
842
|
"_next" => nil,
|
@@ -825,8 +849,8 @@ RSpec.describe "kern:vm_service" do
|
|
825
849
|
dump.controller2_read_sync_res = controller2_read_sync_res;
|
826
850
|
}
|
827
851
|
|
828
|
-
expect(dump["controller1_read_sync_res"]["
|
829
|
-
expect(dump["controller2_read_sync_res"]["
|
852
|
+
expect(dump["controller1_read_sync_res"]["_id"]).to eq("A")
|
853
|
+
expect(dump["controller2_read_sync_res"]["_id"]).to eq("B")
|
830
854
|
end
|
831
855
|
|
832
856
|
it "Calling read_sync on frame0 for page 'B' on controller0 and then on frame1 for page 'A' on controller1 and page 'B' on controller2 will result in all controllers receiving the correct pages (reversed order from above)" do
|
@@ -846,7 +870,7 @@ RSpec.describe "kern:vm_service" do
|
|
846
870
|
@driver.mexpect("if_per_get", ["vm", "spec", "B"], 0)
|
847
871
|
|
848
872
|
#Send the disk read response back for controller0 pageB
|
849
|
-
@driver.int "int_per_get_res", ["vm", "spec", {
|
873
|
+
@driver.int "int_per_get_res", ["vm", "spec", "B", {
|
850
874
|
"_id" => "B",
|
851
875
|
"_hash" => nil,
|
852
876
|
"_next" => nil,
|
@@ -862,7 +886,7 @@ RSpec.describe "kern:vm_service" do
|
|
862
886
|
@driver.mexpect("if_per_get", ["vm", "spec", "A"], 0)
|
863
887
|
|
864
888
|
#Send the disk read response back for frame1 'A' for controller2
|
865
|
-
@driver.int "int_per_get_res", ["vm", "spec", {
|
889
|
+
@driver.int "int_per_get_res", ["vm", "spec", "A", {
|
866
890
|
"_id" => "A",
|
867
891
|
"_hash" => nil,
|
868
892
|
"_next" => nil,
|
@@ -875,8 +899,8 @@ RSpec.describe "kern:vm_service" do
|
|
875
899
|
dump.controller2_read_sync_res = controller2_read_sync_res;
|
876
900
|
}
|
877
901
|
|
878
|
-
expect(dump["controller1_read_sync_res"]["
|
879
|
-
expect(dump["controller2_read_sync_res"]["
|
902
|
+
expect(dump["controller1_read_sync_res"]["_id"]).to eq("A")
|
903
|
+
expect(dump["controller2_read_sync_res"]["_id"]).to eq("B")
|
880
904
|
end
|
881
905
|
|
882
906
|
it "Does send a sync read request from disk cache when watching a key for the first time with sync: true" do
|
@@ -916,45 +940,22 @@ RSpec.describe "kern:vm_service" do
|
|
916
940
|
}.to raise_exception
|
917
941
|
end
|
918
942
|
|
919
|
-
it "
|
920
|
-
ctx = flok_new_user File.read('./spec/kern/assets/vm/
|
921
|
-
|
922
|
-
ctx.eval %{
|
923
|
-
base = _embed("my_controller_sync", 1, {}, null);
|
924
|
-
base2 = _embed("my_controller", base+2, {}, null);
|
925
|
-
|
926
|
-
//Drain queue
|
927
|
-
int_dispatch([]);
|
928
|
-
}
|
929
|
-
|
930
|
-
@driver.ignore_up_to "if_per_get", 0
|
931
|
-
@driver.get "if_per_get", 0
|
932
|
-
|
933
|
-
#There should not be another request for the drive
|
934
|
-
expect {
|
935
|
-
@driver.ignore_up_to "if_per_get"
|
936
|
-
}.to raise_exception
|
937
|
-
end
|
938
|
-
|
939
|
-
it "Sends two disk read request when multiple watches are attempted, and the second watch is sync: true but the disk does not read back before it is requested" do
|
940
|
-
ctx = flok_new_user File.read('./spec/kern/assets/vm/controller8.rb'), File.read("./spec/kern/assets/vm/config4.rb")
|
943
|
+
it "A watch request with the sync flag enabled does trigger a synchronous read for a non-existant page" do
|
944
|
+
ctx = flok_new_user File.read('./spec/kern/assets/vm/controller8ws.rb'), File.read("./spec/kern/assets/vm/config4.rb")
|
941
945
|
|
942
946
|
ctx.eval %{
|
943
947
|
base = _embed("my_controller", 1, {}, null);
|
944
|
-
base2 = _embed("my_controller_sync", base+2, {}, null);
|
945
948
|
|
946
949
|
//Drain queue
|
947
950
|
int_dispatch([]);
|
948
951
|
}
|
949
952
|
|
950
|
-
#The inner controller's on_entry is called before, so it's in reverse order
|
951
953
|
@driver.ignore_up_to "if_per_get", 0
|
952
|
-
@driver.
|
953
|
-
@driver.ignore_up_to "if_per_get", 2
|
954
|
+
@driver.mexpect("if_per_get", ["vm", "spec", "my_key"], 0)
|
954
955
|
end
|
955
956
|
|
956
|
-
it "
|
957
|
-
ctx = flok_new_user File.read('./spec/kern/assets/vm/
|
957
|
+
it "A watch request with the sync flag enabled does return null to read_res if the page does not exist (really an illegal condition, page should always be avaliable if you're doing a watch with sync)" do
|
958
|
+
ctx = flok_new_user File.read('./spec/kern/assets/vm/controller8ws.rb'), File.read("./spec/kern/assets/vm/config4.rb")
|
958
959
|
|
959
960
|
ctx.eval %{
|
960
961
|
base = _embed("my_controller", 1, {}, null);
|
@@ -963,50 +964,36 @@ RSpec.describe "kern:vm_service" do
|
|
963
964
|
int_dispatch([]);
|
964
965
|
}
|
965
966
|
|
966
|
-
|
967
|
-
@driver.
|
968
|
-
|
969
|
-
ctx.eval %{
|
970
|
-
base2 = _embed("my_controller_sync", base+2, {}, null);
|
971
|
-
}
|
967
|
+
@driver.ignore_up_to "if_per_get", 0
|
968
|
+
@driver.mexpect("if_per_get", ["vm", "spec", "my_key"], 0)
|
972
969
|
|
973
|
-
#
|
974
|
-
@driver.
|
975
|
-
@driver.get "if_per_get", 2
|
970
|
+
#Send back a blank page
|
971
|
+
@driver.int "int_per_get_res", ["vm", "spec", "my_key", nil]
|
976
972
|
|
977
|
-
|
978
|
-
expect {
|
979
|
-
@driver.ignore_up_to "if_per_get"
|
980
|
-
}.to raise_exception
|
973
|
+
read_res_params = ctx.dump "read_res_params"
|
974
|
+
expect(read_res_params).to eq({})
|
981
975
|
end
|
982
976
|
|
983
|
-
it "
|
984
|
-
ctx = flok_new_user File.read('./spec/kern/assets/vm/
|
977
|
+
it "A watch request with the sync flag enabled does not send two read_res back after int_dispatch" do
|
978
|
+
ctx = flok_new_user File.read('./spec/kern/assets/vm/controller8ws.rb'), File.read("./spec/kern/assets/vm/config4.rb")
|
985
979
|
|
986
980
|
ctx.eval %{
|
987
|
-
base = _embed("
|
981
|
+
base = _embed("my_controller", 1, {}, null);
|
988
982
|
|
989
983
|
//Drain queue
|
990
984
|
int_dispatch([]);
|
991
985
|
}
|
992
986
|
|
993
987
|
@driver.ignore_up_to "if_per_get", 0
|
994
|
-
@driver.
|
988
|
+
@driver.mexpect("if_per_get", ["vm", "spec", "my_key"], 0)
|
995
989
|
|
996
|
-
|
997
|
-
@driver.int "int_per_get_res", ["vm", "spec",
|
990
|
+
#Send back a blank page
|
991
|
+
@driver.int "int_per_get_res", ["vm", "spec", "my_key", nil]
|
998
992
|
|
999
|
-
ctx.
|
1000
|
-
|
1001
|
-
}
|
1002
|
-
|
1003
|
-
#There should not be another request for the drive
|
1004
|
-
expect {
|
1005
|
-
@driver.ignore_up_to "if_per_get"
|
1006
|
-
}.to raise_exception
|
993
|
+
read_res_params = ctx.dump "read_res_params"
|
994
|
+
expect(read_res_params).to eq({})
|
1007
995
|
end
|
1008
996
|
|
1009
|
-
|
1010
997
|
it "Clears the dirty page when pageout runs" do
|
1011
998
|
ctx = flok_new_user File.read('./spec/kern/assets/vm/controller18.rb'), File.read("./spec/kern/assets/vm/config4.rb")
|
1012
999
|
|
@@ -1134,7 +1121,7 @@ RSpec.describe "kern:vm_service" do
|
|
1134
1121
|
|
1135
1122
|
#And then we let the cache from disk reply, which should be ignored
|
1136
1123
|
#because the cache is already there from the pager
|
1137
|
-
@driver.int "int_per_get_res", ["vm", "spec", page]
|
1124
|
+
@driver.int "int_per_get_res", ["vm", "spec", page["_id"], page]
|
1138
1125
|
|
1139
1126
|
res = JSON.parse(ctx.eval("JSON.stringify(read_res)"))
|
1140
1127
|
expect(res).to eq([
|
@@ -1195,7 +1182,7 @@ RSpec.describe "kern:vm_service" do
|
|
1195
1182
|
|
1196
1183
|
#And then we let the cache from disk reply, which should be ignored
|
1197
1184
|
#because the cache is already there from the pager
|
1198
|
-
@driver.int "int_per_get_res", ["vm", "spec", page]
|
1185
|
+
@driver.int "int_per_get_res", ["vm", "spec", page["_id"], page]
|
1199
1186
|
|
1200
1187
|
res = JSON.parse(ctx.eval("JSON.stringify(read_res)"))
|
1201
1188
|
expect(res).to eq([
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flok
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.67
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- seo
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-07-
|
11
|
+
date: 2015-07-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: execjs
|
@@ -1213,6 +1213,7 @@ files:
|
|
1213
1213
|
- spec/kern/assets/vm/controller19e.rb
|
1214
1214
|
- spec/kern/assets/vm/controller19f.rb
|
1215
1215
|
- spec/kern/assets/vm/controller19g.rb
|
1216
|
+
- spec/kern/assets/vm/controller19h.rb
|
1216
1217
|
- spec/kern/assets/vm/controller2.rb
|
1217
1218
|
- spec/kern/assets/vm/controller20.rb
|
1218
1219
|
- spec/kern/assets/vm/controller21.rb
|
@@ -1224,6 +1225,7 @@ files:
|
|
1224
1225
|
- spec/kern/assets/vm/controller7.rb
|
1225
1226
|
- spec/kern/assets/vm/controller8.rb
|
1226
1227
|
- spec/kern/assets/vm/controller8b.rb
|
1228
|
+
- spec/kern/assets/vm/controller8ws.rb
|
1227
1229
|
- spec/kern/assets/vm/controller9.rb
|
1228
1230
|
- spec/kern/assets/vm/controller_exc_2watch.rb
|
1229
1231
|
- spec/kern/assets/vm/controller_exc_ewatch.rb
|
@@ -2147,6 +2149,7 @@ test_files:
|
|
2147
2149
|
- spec/kern/assets/vm/controller19e.rb
|
2148
2150
|
- spec/kern/assets/vm/controller19f.rb
|
2149
2151
|
- spec/kern/assets/vm/controller19g.rb
|
2152
|
+
- spec/kern/assets/vm/controller19h.rb
|
2150
2153
|
- spec/kern/assets/vm/controller2.rb
|
2151
2154
|
- spec/kern/assets/vm/controller20.rb
|
2152
2155
|
- spec/kern/assets/vm/controller21.rb
|
@@ -2158,6 +2161,7 @@ test_files:
|
|
2158
2161
|
- spec/kern/assets/vm/controller7.rb
|
2159
2162
|
- spec/kern/assets/vm/controller8.rb
|
2160
2163
|
- spec/kern/assets/vm/controller8b.rb
|
2164
|
+
- spec/kern/assets/vm/controller8ws.rb
|
2161
2165
|
- spec/kern/assets/vm/controller9.rb
|
2162
2166
|
- spec/kern/assets/vm/controller_exc_2watch.rb
|
2163
2167
|
- spec/kern/assets/vm/controller_exc_ewatch.rb
|