flok 0.0.79 → 0.0.80
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/kern/pagers/pg_spec.js +5 -0
- data/app/kern/services/vm.rb +56 -2
- data/docs/services/vm.md +25 -3
- data/docs/services/vm/pagers.md +7 -3
- data/docs/todo.md +16 -0
- data/lib/flok/user_compiler.rb +1 -6
- data/lib/flok/version.rb +1 -1
- data/spec/kern/assets/vm/config3.rb +1 -1
- data/spec/kern/assets/vm/config5c.rb +12 -0
- data/spec/kern/assets/vm/controller10.rb +1 -8
- data/spec/kern/assets/vm/controller11.rb +1 -8
- data/spec/kern/controller_spec.rb +0 -12
- data/spec/kern/vm_service_spec.rb +19 -28
- data/spec/kern/vm_service_unsynced_spec.rb +137 -0
- metadata +7 -6
- data/app/kern/pagers/spec0.js +0 -35
- data/app/kern/pagers/spec1.js +0 -24
- data/app/kern/pagers/spec2.js +0 -31
- data/docs/known_issues.md +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0211bf5635601e2e799ddd564e3612c8a02e1354
|
4
|
+
data.tar.gz: 45aa0d364ed30d8a2d01e0ca2d4cb2abcd2ab61b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f47cfbb76f1f5aa170fb8c38963c9df5a2d0179ef617d90c4f7981b733097cf26e6cc4c26c9a74881c1806c40a73a6935d0063ca489c7102630e767e63f59cdd
|
7
|
+
data.tar.gz: 2ab9e84d9daeccf7f11877a4443e8f36a4fcd3ede44cf0cc0ee7ee5a3413c946e9b20d694ee36c131633d8a3c568cc720d798064ca2a4817c441c44f0cb03d63
|
data/app/kern/pagers/pg_spec.js
CHANGED
@@ -6,6 +6,7 @@
|
|
6
6
|
pg_spec<%= i %>_unwatchlist = [];
|
7
7
|
pg_spec<%= i %>_init_params = {ns: ns, options: options};
|
8
8
|
pg_spec<%= i %>_ns = ns;
|
9
|
+
pg_spec<%= i %>_sync_requests = [];
|
9
10
|
}
|
10
11
|
|
11
12
|
function pg_spec<%= i %>_watch(id, page) {
|
@@ -21,5 +22,9 @@
|
|
21
22
|
vm_cache_write(pg_spec<%= i %>_ns, page);
|
22
23
|
vm_transaction_end();
|
23
24
|
}
|
25
|
+
|
26
|
+
function pg_spec<%= i %>_sync(page_id) {
|
27
|
+
pg_spec<%= i %>_sync_requests.push(page_id);
|
28
|
+
}
|
24
29
|
<% end %>
|
25
30
|
<% end %>
|
data/app/kern/services/vm.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
service :vm do
|
2
2
|
global %{
|
3
|
+
//Some of the shared datatypes
|
4
|
+
////////////////////////////////////////////////////////////////////////////////////////////
|
3
5
|
//Cache contains a blank hash for each namespace
|
4
6
|
vm_cache = {
|
5
7
|
<% @options[:pagers].each do |p| %>
|
@@ -13,8 +15,6 @@ service :vm do
|
|
13
15
|
<% end %>
|
14
16
|
};
|
15
17
|
|
16
|
-
//See 'Datatypes & Structures' in ./docs/services/vm.md
|
17
|
-
////////////////////////////////////////////////////////////////////////////////////////////
|
18
18
|
vm_bp_to_nmap = {};
|
19
19
|
vm_pager_waiting_read = {
|
20
20
|
<% @options[:pagers].each do |p| %>
|
@@ -29,6 +29,7 @@ service :vm do
|
|
29
29
|
<%= p[:namespace] %>: {},
|
30
30
|
<% end %>
|
31
31
|
};
|
32
|
+
|
32
33
|
////////////////////////////////////////////////////////////////////////////////////////////
|
33
34
|
|
34
35
|
//Cache
|
@@ -505,6 +506,58 @@ service :vm do
|
|
505
506
|
}
|
506
507
|
}
|
507
508
|
///////////////////////////////////////////////////////////////////////////
|
509
|
+
|
510
|
+
//vm unsynced
|
511
|
+
///////////////////////////////////////////////////////////////////////////
|
512
|
+
//Unsynced page ids to integer vm_unsynced[bp][page_id] = '0' or '1'
|
513
|
+
//where 0 is freshly added and ignored on the first pass of the daemon
|
514
|
+
vm_unsynced = {
|
515
|
+
<% @options[:pagers].each do |p| %>
|
516
|
+
<%= p[:namespace] %>: {},
|
517
|
+
<% end %>
|
518
|
+
};
|
519
|
+
|
520
|
+
function vm_pg_mark_needs_sync(ns, page_id) {
|
521
|
+
//Add to list
|
522
|
+
vm_unsynced[ns][page_id] = 0;
|
523
|
+
|
524
|
+
//Notify pager immediately (daemon will not notify pager on first tick to avoid calling pager's sync to soon)
|
525
|
+
<% @options[:pagers].each do |p| %>
|
526
|
+
<% @options[:pagers].each_with_index do |p, i| %>
|
527
|
+
<% if i == 0 %>
|
528
|
+
if ("<%= p[:namespace] %>" === ns) {
|
529
|
+
<%= p[:name] %>_sync(page_id);
|
530
|
+
}
|
531
|
+
<% else %>
|
532
|
+
else if ("<%= p[:namespace] %>" === ns) {
|
533
|
+
<%= p[:name] %>_sync(page_id);
|
534
|
+
}
|
535
|
+
<% end %>
|
536
|
+
<% end %>
|
537
|
+
<% end %>
|
538
|
+
}
|
539
|
+
|
540
|
+
function vm_pg_unmark_needs_sync(ns, page_id) {
|
541
|
+
delete vm_unsynced[ns][page_id];
|
542
|
+
}
|
543
|
+
|
544
|
+
function vm_pg_sync_wakeup() {
|
545
|
+
//Iterate through all the unsynced entries an increment any entries that are 0 to 1
|
546
|
+
<% @options[:pagers].each do |p| %>
|
547
|
+
//Get all page ids in a namespace
|
548
|
+
var page_ids = Object.keys(vm_unsynced.<%= p[:namespace] %>);
|
549
|
+
|
550
|
+
for (var i = 0; i < page_ids.length; ++i) {
|
551
|
+
if (vm_unsynced.<%= p[:namespace] %>[page_ids[i]] === 0) {
|
552
|
+
vm_unsynced.<%= p[:namespace] %>[page_ids[i]] = 1;
|
553
|
+
} else {
|
554
|
+
//Notify pager
|
555
|
+
<%= p[:name] %>_sync(page_ids[i]);
|
556
|
+
}
|
557
|
+
}
|
558
|
+
<% end %>
|
559
|
+
}
|
560
|
+
///////////////////////////////////////////////////////////////////////////
|
508
561
|
}
|
509
562
|
|
510
563
|
on_wakeup %{
|
@@ -711,5 +764,6 @@ service :vm do
|
|
711
764
|
|
712
765
|
every 20.seconds, %{
|
713
766
|
vm_pageout();
|
767
|
+
vm_pg_sync_wakeup();
|
714
768
|
}
|
715
769
|
end
|
data/docs/services/vm.md
CHANGED
@@ -143,11 +143,23 @@ requested. This is because a cached page will be returned by the call stack whil
|
|
143
143
|
##Cache
|
144
144
|
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.
|
145
145
|
|
146
|
-
###Pageout
|
147
|
-
|
146
|
+
###Pageout, Cache Synchronization, and Pager Synchronization
|
147
|
+
####Pageout Daemon
|
148
|
+
Cache will periodically be synchronized to disk via the `pageout` service. When flok reloads itself, and the `vm` service gets a `watch` the `vm` service will attempt to read from the `vm_cache` first and then read the page from disk (write that disk read to cache).
|
148
149
|
|
149
150
|
Pageout is embodied in the function named `vm_pageout()`. This will asynchronously write `vm_dirty` to disk and clear `vm_dirty` once the write has been commited. `vm_pageout()` is called every minute by the interval timer in this service.
|
150
151
|
|
152
|
+
####Pager Synchronization Daemon
|
153
|
+
When pagers get a write request, many pagers (as in all of them atm) mark the pages via `vm_pg_mark_needs_sync` which first calls the pagers `sync`
|
154
|
+
routine immediately and writes to the `vm_unsynced` hash. The hash is used like `vm_unsynced[ns][page_id]` which yields an integer value. The integer
|
155
|
+
value is either `0` or `1`. When `vm_pg_mark_needs_sync` is first called, the value is set to `0`. When the pager synchronization daemon
|
156
|
+
goes over the list in `vm_unsynced`; the daemon checks the integer field. If the integer is `0`, then the daemon only increments the integer. If the
|
157
|
+
integer is `1`, then the daemon notifies the pager with the `sync` action. The reason this is done is to avoid calling a pagers `sync` function too
|
158
|
+
soon as it is immediately called the first time when the pager calls `vm_pg_mark_needs_sync` on the page (usually at the end of the `write` action
|
159
|
+
for the pager). The pager de-registers the page via `vm_pg_unmark_needs_sync`.
|
160
|
+
|
161
|
+
The pager synchronization daemon is embodied in the function called `vm_pg_sync_wakeup`
|
162
|
+
|
151
163
|
###Datatypes & Structures (Opaque, do not directly modify)
|
152
164
|
* `vm_cache` - The main area for storing the cache. Stored in `vm_cache[ns][key]`. Contains all namespaces by default with blank hashes.
|
153
165
|
* `vm_dirty` - Pages recently written to cache go on the dirty list so that they may be written when the pageout handler runs. Dictionary contains map for `vm_dirty[ns][page._id] => page` for all dirty pages. Pages are removed from the dictionary when they are written in the pageout. Contains all namespaces by default with blank hashes.
|
@@ -159,6 +171,11 @@ Pageout is embodied in the function named `vm_pageout()`. This will asynchronous
|
|
159
171
|
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], ...}`
|
160
172
|
* `vm_pager_waiting_read` - A hash that maps `[ns][page_id]` into a hash that represents a the page that was trying to be written.
|
161
173
|
needed to be read before notifying the pager. Multiple write attempts on the same page before the disk response will undefined behavior.
|
174
|
+
* `vm_unsynced_*`
|
175
|
+
* `vm_unsynced` - A hash that maps `vm_unsynced_fresh[ns][page_id]` to an integer that is either `0` or `1`. the vm sync daemon reads over this
|
176
|
+
queue and `0` means that it was just requested via `vm_pg_mark_needs_sync` and needs to be incremented to `1`. `1` means that the vm sync
|
177
|
+
daemon must contact the pager for the `sync` action. This will happend until the pager calls `vm_pg_unmark_needs_sync` which will remove it
|
178
|
+
from this hash
|
162
179
|
|
163
180
|
##Helper Methods
|
164
181
|
|
@@ -196,9 +213,14 @@ Pageout is embodied in the function named `vm_pageout()`. This will asynchronous
|
|
196
213
|
`__changes_id` of the page matches `changes_id`. If the page is based (implying the base page has changes and the page has changes as all base
|
197
214
|
pages have changes), then if the `changes_id` matches the **base** `__changes_id` , the `__base` is removed from the page. If `changes_id`
|
198
215
|
does not match in either of the cases, then nothing happends. This may happend if a synchronization errousouly comes in.
|
199
|
-
###Non functional
|
216
|
+
###Non functional (functional as is in lambda calculus, or lisp (no **global** state changes but may modify parameters)
|
200
217
|
####Pager specific
|
201
218
|
* `vm_cache_write(ns, page)` - Save a page to cache memory. This will not recalculate the page hash. The page will be stored in `vm_cache[ns][id]` by.
|
219
|
+
* `vm_pg_mark_needs_sync(ns, page_id)` - Marks that a page **in memory** is needing to be synced to the pager. This does a few things:
|
220
|
+
* The page_id is added to the `vm_unsynced` with the value of 0; see above in `Datatypes & Structures` for details. i.e.
|
221
|
+
`vm_unsynced[$PAGER_NS][page_id] = 0`
|
222
|
+
* the pager's routine of `sync` is called immediately. The page must exist in cache at this point.
|
223
|
+
* `vm_pg_unmark_needs_sync(ns, page_id)` - Removes the page from the pending synchronization queue `delete vm_unsynced[$PAGER_NS][page_id]`)
|
202
224
|
|
203
225
|
### <a name='user_page_modification_helpers'></a>User page modification helpers (Controller Macros)
|
204
226
|
You should never directly edit a page in user land; if you do; the pager has no way of knowing that you made modifications. Additionally, if you have multiple controllers watching a page, and it is modified in one controller, those other controllers
|
data/docs/services/vm/pagers.md
CHANGED
@@ -11,6 +11,9 @@ If you haven't already, read [VM Service](../vm.md) for context on pagers.
|
|
11
11
|
* `$NAME_unwatch(id)` - There are no controllers that are watching the page with a page that contains this in the `_id` field
|
12
12
|
* `$NAME_write(page)` - You should write this page, e.g. to network, and/or write to `vm_cache_write`. Alternatively, you can write the page over the network and then let the response from that call `vm_cache_write` in what ever listening code you have.
|
13
13
|
* `page` - A fully constructed page with correctly calculated `_hash` and _sigs on entries.
|
14
|
+
* `$NAME_sync(page_id)` - A page is requested to be synchronized. This was requested by the pager itself by `vm_pg_mark_needs_sync`. Usually,
|
15
|
+
in `write`, a pager will call `vm_pg_mark_needs_sync` which will then invoke `$NAME_sync(page_id)` immediately and on a scheduled interval
|
16
|
+
via the synchronization vm daemon until this pager removes the page from the unsynchronized queues via `vm_pg_unmark_needs_sync`.
|
14
17
|
|
15
18
|
##When are pagers invoked?
|
16
19
|
Pagers handle all requests from controllers except for the following conditions:
|
@@ -28,10 +31,11 @@ The *default memory pager* does not do anything on `watch` or `unwatch`. It depe
|
|
28
31
|
|
29
32
|
####Spec pager | `pg_spec0`, `pg_spec1`
|
30
33
|
This pager does the following when calls are made to it's functions, it's designed to assist with `vm` kernel specs.
|
31
|
-
* `init` - Sets `
|
32
|
-
* `watch` - Appends `{id: id, hash: hash}` to `
|
33
|
-
* `unwatch` - appends id to `
|
34
|
+
* `init` - Sets `pg_specN_init_params` to `{ns: ns, options: options}`
|
35
|
+
* `watch` - Appends `{id: id, hash: hash}` to `pg_specN_watchlist`
|
36
|
+
* `unwatch` - appends id to `pg_specN_unwatchlist`
|
34
37
|
* `write` - Writes the given page to `vm_cache_write`
|
38
|
+
* `sync` - Appends given page_id to `pg_specN_sync_requests`
|
35
39
|
|
36
40
|
These pagers only exists if the environment is in `DEBUG` mode (`@debug` is enabled).
|
37
41
|
|
data/docs/todo.md
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#Todo
|
2
|
+
|
3
|
+
###Known issues & Bugs
|
4
|
+
|
5
|
+
0. A `every` event used in a controller's action will time correctly on the first action, but subsequent actions will be off by at most 3 ticks.
|
6
|
+
This is because we do not have any way (currently) to reset the timing queue in the controller as it reisters for all timing events at init. See
|
7
|
+
"Does not call intervals of other actions; and still works when switching back actions" in `spec/kern/controller_spec.rb`
|
8
|
+
1. `vm_cache_write_sync_pending` in the `vm` service relies on page_ids, but this would cause a collision on two pages named the same thing. This
|
9
|
+
needs to integrate the namespace.
|
10
|
+
2. The pager synchronization daemon and functions associated with marking paging as needing synchronization will attempt to sync at one time and not
|
11
|
+
store the data if there is a crash or exit before synchronization completes. Furethermore, too many unsynced pages will wreck havok as they wil be
|
12
|
+
dispatched at the same time via the synchronization daemon.
|
13
|
+
|
14
|
+
###Ideas for improvement
|
15
|
+
0. The `Raise` function should not actually signal the controller, it could just inline that
|
16
|
+
1. The controller's `ctable` could be flattened.
|
data/lib/flok/user_compiler.rb
CHANGED
@@ -494,7 +494,7 @@ module Flok
|
|
494
494
|
end
|
495
495
|
|
496
496
|
class UserCompilerAction
|
497
|
-
attr_accessor :controller, :name, :ons, :every_handlers
|
497
|
+
attr_accessor :controller, :name, :ons, :every_handlers
|
498
498
|
include UserCompilerMacro
|
499
499
|
|
500
500
|
def initialize controller, name, ctx, &block
|
@@ -504,7 +504,6 @@ module Flok
|
|
504
504
|
@_on_entry_src = ""
|
505
505
|
@ons = [] #Event handlers
|
506
506
|
@every_handlers = []
|
507
|
-
@on_entry_has_goto = false
|
508
507
|
|
509
508
|
self.instance_eval(&block)
|
510
509
|
end
|
@@ -512,8 +511,6 @@ module Flok
|
|
512
511
|
def on_entry js_src
|
513
512
|
#returns a string
|
514
513
|
@_on_entry_src = _macro(js_src)
|
515
|
-
|
516
|
-
@on_entry_has_goto = (js_src =~ /Goto/) != nil
|
517
514
|
end
|
518
515
|
|
519
516
|
def on_entry_src
|
@@ -585,8 +582,6 @@ module Flok
|
|
585
582
|
|
586
583
|
def choose_action &block
|
587
584
|
@ctx.action self, :choose_action, &block
|
588
|
-
|
589
|
-
raise "choose_action must contain Goto" unless @ctx.actions.detect{|e| e.name == :choose_action}.on_entry_has_goto
|
590
585
|
end
|
591
586
|
|
592
587
|
#Names of spots
|
data/lib/flok/version.rb
CHANGED
@@ -3,14 +3,7 @@ controller :my_controller do
|
|
3
3
|
|
4
4
|
action :my_action do
|
5
5
|
on_entry %{
|
6
|
-
var
|
7
|
-
hello: "world"
|
8
|
-
}
|
9
|
-
|
10
|
-
page = NewPage("array", "test");
|
11
|
-
SetPageHead(page, "head");
|
12
|
-
SetPageNext(page, "next");
|
13
|
-
EntryInsert(page, 0, entry);
|
6
|
+
var page = vm_create_page("test");
|
14
7
|
|
15
8
|
var info = {
|
16
9
|
ns: "spec",
|
@@ -3,14 +3,7 @@ controller :my_controller do
|
|
3
3
|
|
4
4
|
action :my_action do
|
5
5
|
on_entry %{
|
6
|
-
var
|
7
|
-
hello: "world"
|
8
|
-
}
|
9
|
-
|
10
|
-
page = NewPage("array", "test");
|
11
|
-
SetPageHead(page, "head");
|
12
|
-
SetPageNext(page, "next");
|
13
|
-
EntryInsert(page, 0, entry);
|
6
|
+
var page = vm_create_page("test");
|
14
7
|
|
15
8
|
var watch_info = {
|
16
9
|
ns: "spec",
|
@@ -979,18 +979,6 @@ RSpec.describe "kern:controller_spec" do
|
|
979
979
|
@driver.mexpect("if_event", [Integer, "action", {"from" => nil, "to" => "index"}])
|
980
980
|
end
|
981
981
|
|
982
|
-
it "Not setting a Goto will result in an exception" do
|
983
|
-
expect {
|
984
|
-
ctx = flok_new_user File.read('./spec/kern/assets/choose_action_sync_no_goto.rb'), File.read("./spec/kern/assets/test_service/config0.rb")
|
985
|
-
ctx.evald %{
|
986
|
-
base = _embed("my_controller", 0, {}, null);
|
987
|
-
|
988
|
-
//Drain queue
|
989
|
-
int_dispatch([]);
|
990
|
-
}
|
991
|
-
}.to raise_exception
|
992
|
-
end
|
993
|
-
|
994
982
|
it "Does support using a macro that contains current_action" do
|
995
983
|
ctx = flok_new_user File.read('./spec/kern/assets/current_action_nav.rb')
|
996
984
|
dump = ctx.evald %{
|
@@ -39,21 +39,12 @@ RSpec.describe "kern:vm_service" do
|
|
39
39
|
|
40
40
|
#Run the check
|
41
41
|
res = ctx.eval %{
|
42
|
-
|
43
|
-
page = {
|
44
|
-
_head: "a",
|
45
|
-
_next: "b",
|
46
|
-
_type: "array",
|
47
|
-
_id: "hello",
|
48
|
-
entries: [
|
49
|
-
{_id: "hello2", _sig: "nohteunth"},
|
50
|
-
]
|
51
|
-
}
|
52
|
-
|
53
|
-
vm_rehash_page(page);
|
42
|
+
var page = vm_create_page("test");
|
54
43
|
|
55
44
|
//Save page
|
45
|
+
vm_transaction_begin();
|
56
46
|
vm_cache_write("user", page);
|
47
|
+
vm_transaction_end();
|
57
48
|
}
|
58
49
|
|
59
50
|
vm_cache = JSON.parse(ctx.eval("JSON.stringify(vm_cache)"))
|
@@ -114,20 +105,12 @@ RSpec.describe "kern:vm_service" do
|
|
114
105
|
//which receives a call to watch with the hash of this page so the
|
115
106
|
//watch function can tell if the page has changed (e.g. if you are connecting)
|
116
107
|
//to a remote server
|
117
|
-
page =
|
118
|
-
_head: "a",
|
119
|
-
_next: "b",
|
120
|
-
_id: "my_key",
|
121
|
-
_type: "array",
|
122
|
-
entries: [
|
123
|
-
{_id: "hello2", _sig: "nohteunth"},
|
124
|
-
]
|
125
|
-
}
|
126
|
-
|
127
|
-
vm_rehash_page(page);
|
108
|
+
var page = vm_create_page("test");
|
128
109
|
|
129
110
|
//Save page for the spec pager
|
111
|
+
vm_transaction_begin();
|
130
112
|
vm_cache_write("spec", page);
|
113
|
+
vm_transaction_end();
|
131
114
|
}
|
132
115
|
|
133
116
|
#This hash was calculated during vm_rehash_page
|
@@ -144,10 +127,7 @@ RSpec.describe "kern:vm_service" do
|
|
144
127
|
pg_spec0_watchlist = JSON.parse(ctx.eval("JSON.stringify(pg_spec0_watchlist)"))
|
145
128
|
|
146
129
|
#Expect options and ns to match in config4
|
147
|
-
expect(pg_spec0_watchlist).to eq(
|
148
|
-
"id" => "my_key",
|
149
|
-
"page" => page
|
150
|
-
}])
|
130
|
+
expect(pg_spec0_watchlist[0]["id"]).to eq("my_key")
|
151
131
|
end
|
152
132
|
|
153
133
|
it "does not throw an exception if multiple watches are attempted" do
|
@@ -351,6 +331,8 @@ RSpec.describe "kern:vm_service" do
|
|
351
331
|
int_dispatch([]);
|
352
332
|
}
|
353
333
|
|
334
|
+
@driver.int "int_per_get_res", ["vm", "spec", "test", nil]
|
335
|
+
|
354
336
|
#Expect the page to be written to cache
|
355
337
|
vm_cache = JSON.parse(ctx.eval("JSON.stringify(vm_cache)"));
|
356
338
|
vm_write_list = JSON.parse(ctx.eval("JSON.stringify(vm_write_list[0])"));
|
@@ -367,8 +349,17 @@ RSpec.describe "kern:vm_service" do
|
|
367
349
|
int_dispatch([]);
|
368
350
|
}
|
369
351
|
|
370
|
-
|
352
|
+
#Write will attempt to read disk first
|
353
|
+
@driver.int "int_per_get_res", ["vm", "spec", "test", nil]
|
354
|
+
|
355
|
+
#Read is asynchronous
|
356
|
+
ctx.eval %{
|
357
|
+
//Drain queue
|
358
|
+
int_dispatch([]);
|
359
|
+
}
|
360
|
+
|
371
361
|
vm_write_list = JSON.parse(ctx.eval("JSON.stringify(vm_write_list[0])"));
|
362
|
+
read_res_params = JSON.parse(ctx.eval("JSON.stringify(read_res_params)"))
|
372
363
|
expect(read_res_params).to eq(vm_write_list)
|
373
364
|
end
|
374
365
|
|
@@ -0,0 +1,137 @@
|
|
1
|
+
#The vm service
|
2
|
+
|
3
|
+
Dir.chdir File.join File.dirname(__FILE__), '../../'
|
4
|
+
require './spec/env/kern.rb'
|
5
|
+
require './spec/lib/helpers.rb'
|
6
|
+
require './spec/lib/io_extensions.rb'
|
7
|
+
require './spec/lib/rspec_extensions.rb'
|
8
|
+
require 'zlib'
|
9
|
+
|
10
|
+
RSpec.describe "kern:vm_service" do
|
11
|
+
include Zlib
|
12
|
+
include_context "kern"
|
13
|
+
|
14
|
+
it "vm_pg_mark_needs_sync does call the pagers sync routine and adds an entry in the vm_unsynced table with a value of 0" do
|
15
|
+
ctx = flok_new_user File.read('./spec/kern/assets/vm/controller0.rb'), File.read("./spec/kern/assets/vm/config5c.rb")
|
16
|
+
dump = ctx.evald %{
|
17
|
+
//Needed to initialize pagers
|
18
|
+
base = _embed("my_controller", 0, {}, null);
|
19
|
+
|
20
|
+
vm_pg_mark_needs_sync("spec", "test");
|
21
|
+
|
22
|
+
dump.vm_unsynced = vm_unsynced;
|
23
|
+
dump.pg_spec0_sync_requests = pg_spec0_sync_requests;
|
24
|
+
}
|
25
|
+
|
26
|
+
expect(dump["vm_unsynced"]).to eq({
|
27
|
+
"spec" => {
|
28
|
+
"test" => 0
|
29
|
+
}
|
30
|
+
})
|
31
|
+
|
32
|
+
expect(dump["pg_spec0_sync_requests"]).to eq(["test"])
|
33
|
+
end
|
34
|
+
|
35
|
+
it "vm_pg_unmark_needs_sync does remove the entry from the vm_unsynced table and does not fail if the entry does not exist" do
|
36
|
+
ctx = flok_new_user File.read('./spec/kern/assets/vm/controller0.rb'), File.read("./spec/kern/assets/vm/config5c.rb")
|
37
|
+
dump = ctx.evald %{
|
38
|
+
//Needed to initialize pagers
|
39
|
+
base = _embed("my_controller", 0, {}, null);
|
40
|
+
|
41
|
+
vm_pg_mark_needs_sync("spec", "test");
|
42
|
+
vm_pg_unmark_needs_sync("spec", "test");
|
43
|
+
vm_pg_unmark_needs_sync("spec", "test_non_existant_key");
|
44
|
+
|
45
|
+
dump.vm_unsynced = vm_unsynced;
|
46
|
+
}
|
47
|
+
|
48
|
+
expect(dump["vm_unsynced"]).to eq({
|
49
|
+
"spec" => {
|
50
|
+
}
|
51
|
+
})
|
52
|
+
end
|
53
|
+
|
54
|
+
#Don't sync when it's 0 because the pager just added it and we don't want to sync to early. Wait til next pass
|
55
|
+
it "vm_pg_sync_wakeup does increment any entries that are currently 0 to the value of 1 and does not invoke pager's sync for those entries" do
|
56
|
+
ctx = flok_new_user File.read('./spec/kern/assets/vm/controller0.rb'), File.read("./spec/kern/assets/vm/config5c.rb")
|
57
|
+
dump = ctx.evald %{
|
58
|
+
//Needed to initialize pagers
|
59
|
+
base = _embed("my_controller", 0, {}, null);
|
60
|
+
|
61
|
+
vm_pg_mark_needs_sync("spec", "test");
|
62
|
+
vm_pg_sync_wakeup();
|
63
|
+
|
64
|
+
dump.vm_unsynced = vm_unsynced;
|
65
|
+
dump.pg_spec0_sync_requests = pg_spec0_sync_requests;
|
66
|
+
}
|
67
|
+
|
68
|
+
expect(dump["vm_unsynced"]).to eq({
|
69
|
+
"spec" => {
|
70
|
+
"test" => 1
|
71
|
+
}
|
72
|
+
})
|
73
|
+
|
74
|
+
#Only expect one entry, wakeup should have skipped the first try
|
75
|
+
expect(dump["pg_spec0_sync_requests"]).to eq(["test"])
|
76
|
+
end
|
77
|
+
|
78
|
+
it "vm_pg_sync_wakeup does *not* increment any entries that are currently 1 and *does* invoke pager's sync for those entries" do
|
79
|
+
ctx = flok_new_user File.read('./spec/kern/assets/vm/controller0.rb'), File.read("./spec/kern/assets/vm/config5c.rb")
|
80
|
+
dump = ctx.evald %{
|
81
|
+
//Needed to initialize pagers
|
82
|
+
base = _embed("my_controller", 0, {}, null);
|
83
|
+
|
84
|
+
vm_pg_mark_needs_sync("spec", "test");
|
85
|
+
vm_pg_sync_wakeup();
|
86
|
+
vm_pg_sync_wakeup();
|
87
|
+
|
88
|
+
dump.vm_unsynced = vm_unsynced;
|
89
|
+
dump.pg_spec0_sync_requests = pg_spec0_sync_requests;
|
90
|
+
}
|
91
|
+
|
92
|
+
expect(dump["vm_unsynced"]).to eq({
|
93
|
+
"spec" => {
|
94
|
+
"test" => 1
|
95
|
+
}
|
96
|
+
})
|
97
|
+
|
98
|
+
#This time, we expect two entries because the second vm_sync_wakeup should have triggered it.
|
99
|
+
expect(dump["pg_spec0_sync_requests"]).to eq(["test", "test"])
|
100
|
+
end
|
101
|
+
|
102
|
+
it "vm_pg_sync_wakeup is called every 20 seconds" do
|
103
|
+
ctx = flok_new_user File.read('./spec/kern/assets/vm/controller0.rb'), File.read("./spec/kern/assets/vm/config5c.rb")
|
104
|
+
|
105
|
+
#Mark page as needing sync
|
106
|
+
dump = ctx.evald %{
|
107
|
+
//Needed to initialize pagers
|
108
|
+
base = _embed("my_controller", 0, {}, null);
|
109
|
+
|
110
|
+
vm_pg_mark_needs_sync("spec", "test");
|
111
|
+
}
|
112
|
+
|
113
|
+
#Call the timer for 1 shot
|
114
|
+
(20*4).times do
|
115
|
+
@driver.int "int_timer", []
|
116
|
+
end
|
117
|
+
|
118
|
+
#First time, the vm_pg_sync_wakeup should not have triggered anything (vm_unsynced still set to 0)
|
119
|
+
expect(ctx.dump("pg_spec0_sync_requests")).to eq(["test"])
|
120
|
+
|
121
|
+
#Call the timer for 1 more shot
|
122
|
+
(20*4).times do
|
123
|
+
@driver.int "int_timer", []
|
124
|
+
end
|
125
|
+
|
126
|
+
#Second time, vm_pg_sync_wakeup should call pager's sync function
|
127
|
+
expect(ctx.dump("pg_spec0_sync_requests")).to eq(["test", "test"])
|
128
|
+
|
129
|
+
#Call the timer for 1 more shot
|
130
|
+
(20*4).times do
|
131
|
+
@driver.int "int_timer", []
|
132
|
+
end
|
133
|
+
|
134
|
+
#Third time, vm_pg_sync_wakeup should call pager's sync function
|
135
|
+
expect(ctx.dump("pg_spec0_sync_requests")).to eq(["test", "test", "test"])
|
136
|
+
end
|
137
|
+
end
|
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.80
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- seo
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-08-
|
11
|
+
date: 2015-08-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: execjs
|
@@ -314,9 +314,6 @@ files:
|
|
314
314
|
- app/kern/pagers/pg_net_sim.js
|
315
315
|
- app/kern/pagers/pg_sockio.js
|
316
316
|
- app/kern/pagers/pg_spec.js
|
317
|
-
- app/kern/pagers/spec0.js
|
318
|
-
- app/kern/pagers/spec1.js
|
319
|
-
- app/kern/pagers/spec2.js
|
320
317
|
- app/kern/services/rest.rb
|
321
318
|
- app/kern/services/test.rb
|
322
319
|
- app/kern/services/vm.rb
|
@@ -340,7 +337,6 @@ files:
|
|
340
337
|
- docs/images/view_and_spot.png
|
341
338
|
- docs/interactive.md
|
342
339
|
- docs/kernel_api.md
|
343
|
-
- docs/known_issues.md
|
344
340
|
- docs/messaging.md
|
345
341
|
- docs/mod/controller.md
|
346
342
|
- docs/mod/debug.md
|
@@ -364,6 +360,7 @@ files:
|
|
364
360
|
- docs/services/vm/diff.md
|
365
361
|
- docs/services/vm/pagers.md
|
366
362
|
- docs/testing.md
|
363
|
+
- docs/todo.md
|
367
364
|
- flok.gemspec
|
368
365
|
- lib/flok.rb
|
369
366
|
- lib/flok/build.rb
|
@@ -1208,6 +1205,7 @@ files:
|
|
1208
1205
|
- spec/kern/assets/vm/config4.rb
|
1209
1206
|
- spec/kern/assets/vm/config5.rb
|
1210
1207
|
- spec/kern/assets/vm/config5b.rb
|
1208
|
+
- spec/kern/assets/vm/config5c.rb
|
1211
1209
|
- spec/kern/assets/vm/config6.rb
|
1212
1210
|
- spec/kern/assets/vm/controller0.rb
|
1213
1211
|
- spec/kern/assets/vm/controller0_diff.rb
|
@@ -1306,6 +1304,7 @@ files:
|
|
1306
1304
|
- spec/kern/vm_service_mem_pagers_spec.rb
|
1307
1305
|
- spec/kern/vm_service_net_sim_pager_spec.rb
|
1308
1306
|
- spec/kern/vm_service_spec.rb
|
1307
|
+
- spec/kern/vm_service_unsynced_spec.rb
|
1309
1308
|
- spec/kern/vm_sockio_pager_spec.rb
|
1310
1309
|
- spec/kern/vm_transaction_spec.rb
|
1311
1310
|
- spec/lib/helpers.rb
|
@@ -2156,6 +2155,7 @@ test_files:
|
|
2156
2155
|
- spec/kern/assets/vm/config4.rb
|
2157
2156
|
- spec/kern/assets/vm/config5.rb
|
2158
2157
|
- spec/kern/assets/vm/config5b.rb
|
2158
|
+
- spec/kern/assets/vm/config5c.rb
|
2159
2159
|
- spec/kern/assets/vm/config6.rb
|
2160
2160
|
- spec/kern/assets/vm/controller0.rb
|
2161
2161
|
- spec/kern/assets/vm/controller0_diff.rb
|
@@ -2254,6 +2254,7 @@ test_files:
|
|
2254
2254
|
- spec/kern/vm_service_mem_pagers_spec.rb
|
2255
2255
|
- spec/kern/vm_service_net_sim_pager_spec.rb
|
2256
2256
|
- spec/kern/vm_service_spec.rb
|
2257
|
+
- spec/kern/vm_service_unsynced_spec.rb
|
2257
2258
|
- spec/kern/vm_sockio_pager_spec.rb
|
2258
2259
|
- spec/kern/vm_transaction_spec.rb
|
2259
2260
|
- spec/lib/helpers.rb
|
data/app/kern/pagers/spec0.js
DELETED
@@ -1,35 +0,0 @@
|
|
1
|
-
<% if @debug %>
|
2
|
-
spec0_data = {};
|
3
|
-
spec0_read_count = 0;
|
4
|
-
|
5
|
-
function spec0_init(options) {
|
6
|
-
spec0_init_options = options;
|
7
|
-
}
|
8
|
-
|
9
|
-
function spec0_read_sync(ns, bp, key) {
|
10
|
-
spec0_read_count += 1;
|
11
|
-
|
12
|
-
var info = {
|
13
|
-
key: key,
|
14
|
-
value: spec0_data[key],
|
15
|
-
}
|
16
|
-
int_event(bp, "read_res", info);
|
17
|
-
//vm_cache[ns][key] = spec0_data[key];
|
18
|
-
}
|
19
|
-
|
20
|
-
function spec0_read(ns, bp, key) {
|
21
|
-
spec0_read_count += 1;
|
22
|
-
|
23
|
-
var info = {
|
24
|
-
key: key,
|
25
|
-
value: spec0_data[key],
|
26
|
-
}
|
27
|
-
|
28
|
-
int_event(bp, "read_res", info);
|
29
|
-
vm_cache_write(ns, key, spec0_data[key]);
|
30
|
-
}
|
31
|
-
|
32
|
-
function spec0_write(key, value) {
|
33
|
-
spec0_data[key] = value;
|
34
|
-
}
|
35
|
-
<% end %>
|
data/app/kern/pagers/spec1.js
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
<% if @debug %>
|
2
|
-
spec1_value = "a";
|
3
|
-
|
4
|
-
function spec1_init(options) {
|
5
|
-
spec1_init_options = options;
|
6
|
-
}
|
7
|
-
|
8
|
-
function spec1_read_sync(ns, bp, key) {
|
9
|
-
throw "unsupported"
|
10
|
-
}
|
11
|
-
|
12
|
-
function spec1_read(ns, bp, key) {
|
13
|
-
var info = {
|
14
|
-
key: key,
|
15
|
-
value: spec1_value,
|
16
|
-
}
|
17
|
-
|
18
|
-
int_event(bp, "read_res", info);
|
19
|
-
vm_cache_write(ns, key, spec1_value);
|
20
|
-
|
21
|
-
//Now change the value
|
22
|
-
spec1_value = "b";
|
23
|
-
}
|
24
|
-
<% end %>
|
data/app/kern/pagers/spec2.js
DELETED
@@ -1,31 +0,0 @@
|
|
1
|
-
<% if @debug %>
|
2
|
-
spec2_value = "a";
|
3
|
-
|
4
|
-
function spec2_init(options) {
|
5
|
-
spec2_init_options = options;
|
6
|
-
}
|
7
|
-
|
8
|
-
function spec2_read_sync(ns, bp, key) {
|
9
|
-
throw "unsupported"
|
10
|
-
}
|
11
|
-
|
12
|
-
function spec2_read(ns, bp, key) {
|
13
|
-
var info = {
|
14
|
-
key: key,
|
15
|
-
value: spec2_value,
|
16
|
-
}
|
17
|
-
|
18
|
-
int_event(bp, "read_res", info);
|
19
|
-
vm_cache_write(ns, key, spec2_value);
|
20
|
-
|
21
|
-
//Now change the value
|
22
|
-
spec2_value = "b";
|
23
|
-
}
|
24
|
-
|
25
|
-
function spec2_watch(ns, key) {
|
26
|
-
}
|
27
|
-
|
28
|
-
function spec2_spec_trigger() {
|
29
|
-
vm_notify("user", "my_key");
|
30
|
-
}
|
31
|
-
<% end %>
|
data/docs/known_issues.md
DELETED
@@ -1,7 +0,0 @@
|
|
1
|
-
#Known issues & Bugs
|
2
|
-
|
3
|
-
0000. A `every` event used in a controller's action will time correctly on the first action, but subsequent actions will be off by at most 3 ticks.
|
4
|
-
This is because we do not have any way (currently) to reset the timing queue in the controller as it reisters for all timing events at init. See
|
5
|
-
"Does not call intervals of other actions; and still works when switching back actions" in `spec/kern/controller_spec.rb`
|
6
|
-
0002. `vm_cache_write_sync_pending` in the `vm` service relies on page_ids, but this would cause a collision on two pages named the same thing. This
|
7
|
-
needs to integrate the namespace.
|