flok 0.0.79 → 0.0.80
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/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.
|