@naanlang/naan 1.2.0 → 1.2.1

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.
@@ -52,7 +52,7 @@ closure ExecutorBase(track, type, name, local exec) {
52
52
  }
53
53
 
54
54
  // execReceived
55
- // THe specified message was received from the instance, so signal it.
55
+ // The specified message was received from the instance, so signal it.
56
56
 
57
57
  exec.execReceived = closure execReceived(data, local pending) {
58
58
  pending = exec.pending[data.xid]
@@ -65,6 +65,13 @@ closure ExecutorBase(track, type, name, local exec) {
65
65
  pending.signal(list(false, data))
66
66
  }
67
67
 
68
+ // execSetStatus
69
+ // Received a status update from the instance.
70
+
71
+ exec.execSetStatus = function execSetStatus(status) {
72
+ exec.xstatus = status
73
+ }
74
+
68
75
  // execFailed
69
76
  // Communication has failed.
70
77
 
@@ -263,21 +270,22 @@ closure ExecutorContext(exec, contextID, local context, util) {
263
270
  *
264
271
  * Allowable options are:
265
272
  * {
266
- * maxcount: <integer> // maximum workers, default 4
267
- * initeval: `(<expr>, <put>, <get>) // initializes each new worker
268
- * basename: <string> // worker label for UI, default "batch"
273
+ * spawnLoc: <string> // e.g. "Local" (default) or "Host"
274
+ * maxcount: <integer> // maximum workers, default 4
275
+ * initeval: `(<expr>, <put>, <get>) // initializes each new worker
276
+ * basename: <string> // worker label for UI, default "batch"
269
277
  * }
270
278
  *
271
279
  */
272
280
 
273
- closure ExecutorParallel(options, local maxcount, basename, parallel, exqueue, crValue) {
281
+ closure ExecutorParallel(track, options, local maxcount, parallel, exqueue, crValue) {
274
282
  global()
283
+ options = merge({
284
+ spawnLoc: "Local"
285
+ maxcount: 4
286
+ basename: "batch"
287
+ }, options)
275
288
  maxcount = options.maxcount
276
- if !maxcount
277
- maxcount = 4 // default is 4 workers
278
- basename = options.basename
279
- if !string(basename)
280
- basename = "batch"
281
289
  exqueue = [] // waiting for execution
282
290
  parallel = new(object, this)
283
291
  parallel.workers = [] // array of worker executors
@@ -288,36 +296,41 @@ closure ExecutorParallel(options, local maxcount, basename, parallel, exqueue, c
288
296
  //
289
297
  // Return the next available worker. If no workers are available and we haven't hit the maximum
290
298
  // then create an additional worker and return it. If we cannot allocate another worker then this
291
- // returns false.
299
+ // returns { wait: true }.
292
300
 
293
301
  closure acquireWorker(local workdex, name, worker, context, result) {
294
302
  if parallel.available.length > 0
295
- return (parallel.available.pop())
303
+ return (list(false, parallel.available.pop()))
296
304
  workdex = parallel.workers.length
297
305
  if workdex >= maxcount
298
- return (false)
306
+ return (list(false, { wait: true }))
299
307
  parallel.workers[workdex] = false // reserve our spot
300
- name = basename.concat("-", workdex+1)
301
- worker = App.nide.track.spawn("Local", name, "ExecutorParallel") // ### App.nide.track.spawn may not exist
302
- if worker.0 { // ### wasting space on workers list
308
+ name = options.basename.concat("-", workdex+1)
309
+ worker = track.spawn(options.spawnLoc, name, {
310
+ workerID: "ExecutorParallel"
311
+ })
312
+ if worker.0 {
313
+ parallel.workers.splice(workdex, 1)
303
314
  debuglog("execParallel: cannot spawn worker:", ErrorString(worker.0))
304
- return (false)
315
+ return (list(worker.0))
305
316
  }
306
317
  worker = worker.1
307
318
  context = worker.context()
308
319
  if context.0 {
309
- debuglog("execParallel: cannot create worker context:", ErrorString(context.0))
320
+ parallel.workers.splice(workdex, 1)
310
321
  worker.destroy()
311
- return (false)
322
+ debuglog("execParallel: cannot create worker context:", ErrorString(context.0))
323
+ return (list(context.0))
312
324
  }
313
325
  context = context.1
314
326
  parallel.workers[workdex] = worker
315
327
  parallel.contexts[worker] = context
316
328
  if tuple(options.initeval) {
317
329
  result = apply(context.eval, options.initeval)
318
- if result.0
319
- debuglog("execParallel: cannot initialize worker", name, ErrorString(result.0)) }
320
- return (worker)
330
+ if result.0 {
331
+ debuglog("execParallel: cannot initialize worker", name, ErrorString(result.0))
332
+ return (list(result.0)) } }
333
+ return (list(false, worker))
321
334
  }
322
335
 
323
336
  // releaseWorker
@@ -337,23 +350,26 @@ closure ExecutorParallel(options, local maxcount, basename, parallel, exqueue, c
337
350
  // don't remove work from the queue until we already have a worker.
338
351
  //
339
352
 
340
- closure execNext(local worker, result) {
353
+ closure execNext(local error, worker, result) {
341
354
  if exqueue.length > 0 {
342
- worker = acquireWorker() // false if none available
343
- if !worker {
344
- if maxcount > 0 && parallel.workers.length == 0 // maxcount zero when being destroyed
345
- throw("execParallel: cannot allocate any workers at all")
346
- return // we're busy, so try again later
355
+ `(error, worker) = acquireWorker()
356
+ if error {
357
+ if maxcount > 0 && parallel.workers.length == 0 {
358
+ exqueue = []
359
+ throw("execParallel: cannot allocate any workers at all") }
360
+ return // one failed, so try again later
347
361
  }
362
+ if worker.wait
363
+ return // we're busy, so try again later
348
364
  future(function(local next, context) {
349
365
  next = exqueue.splice(0, 1).0 // remove oldest entry, from start
350
366
  if !next {
351
367
  releaseWorker(worker) // someone else already processed this
352
368
  return
353
- }
369
+ }
354
370
  context = parallel.contexts[worker]
355
371
  if next.eval
356
- result = apply(context.eval, next.args)
372
+ result = apply(context.eval, next.eval)
357
373
  else if next.proc
358
374
  result = context.rpc(next.proc, next.args)
359
375
  else
@@ -372,7 +388,7 @@ closure ExecutorParallel(options, local maxcount, basename, parallel, exqueue, c
372
388
  //
373
389
 
374
390
  parallel.eval = closure evalf(expr, put, get, local pending) {
375
- if !maxcount
391
+ if maxcount == 0
376
392
  return (crValue) // already destroyed
377
393
  pending = new(nonce)
378
394
  exqueue.push({
@@ -392,13 +408,55 @@ closure ExecutorParallel(options, local maxcount, basename, parallel, exqueue, c
392
408
  evalf(expr, eval(put), eval(get))
393
409
  }
394
410
 
411
+ // exBatch
412
+ //
413
+ // Remote helper to execute a batch function.
414
+ //
415
+
416
+ closure exBatch(expr, local pending) {
417
+ // evaluate the expression in batch mode
418
+ function execbat() {
419
+ try {
420
+ pending.signal(list(false, evalactive(expr)))
421
+ } catch {
422
+ pending.signal(list(Error(exception)))
423
+ }
424
+ }
425
+
426
+ pending = new(nonce)
427
+ exec(list(execbat))
428
+ pending.wait()
429
+ }
430
+
431
+ // batch
432
+ //
433
+ // Execute eval above in a remote in batch mode, waiting until it is complete.
434
+ //
435
+
436
+ parallel.batch = closure batchf(expr, put, get, local result) {
437
+ result = evalf(list(exBatch, list(quote, expr)), `(exBatch).append(put), get)
438
+ if result.0 // unpack our error wrapper
439
+ result
440
+ else
441
+ result.1
442
+ }
443
+
444
+ // batchq
445
+ //
446
+ // Evaluate the specified QUOTED expression in a remote in batch mode.
447
+ //
448
+
449
+ parallel.batchq = macro batchq(expr, put, get) {
450
+ batchf(expr, eval(put), eval(get))
451
+ }
452
+
395
453
  // rpc
396
454
  //
397
455
  // Execute a procedure call in a remote worker.
398
456
  //
399
457
 
400
458
  parallel.rpc = closure rpc(proc, args, local pending) {
401
- if !maxcount
459
+ if maxcount == 0
402
460
  return (crValue) // already destroyed
403
461
  pending = new(nonce)
404
462
  exqueue.push({
@@ -410,13 +468,36 @@ closure ExecutorParallel(options, local maxcount, basename, parallel, exqueue, c
410
468
  pending.wait()
411
469
  }
412
470
 
471
+ // status
472
+ //
473
+ // Report status of workers. Each worker has a dictionary:
474
+ // {
475
+ // state: <string> // "active" or "idle"
476
+ // status: <dict> // like runaverage(1)
477
+ // }
478
+ //
479
+
480
+ parallel.status = function status(local output, worker) {
481
+ output = []
482
+ for worker in parallel.workers {
483
+ output.push({
484
+ name: worker.name
485
+ type: worker.type
486
+ state: if parallel.available.indexOf(worker) >= 0
487
+ "idle" else "active"
488
+ status: worker.xstatus
489
+ })
490
+ }
491
+ output
492
+ }
493
+
413
494
  // destroy
414
495
  //
415
496
  // Destroy the object by destroying the workers and failing pending requests with cancelResult.
416
497
  //
417
498
 
418
499
  parallel.destroy = closure destroy(cancelResult, local worker, next) {
419
- if !maxcount
500
+ if maxcount == 0
420
501
  return (false) // already destroyed
421
502
  crValue = cancelResult
422
503
  maxcount = 0
@@ -542,6 +623,13 @@ closure ExecutorTracker(local xtrak) {
542
623
  } (pop(args), args)
543
624
  }
544
625
 
626
+ // parallel
627
+ // Return a new parallel executor with specified options.
628
+
629
+ xtrak.parallel = function parallel(options) {
630
+ ExecutorParallel(xtrak, options)
631
+ }
632
+
545
633
  xtrak.register(execLambda, "Lambda")
546
634
 
547
635
  // finis
@@ -526,7 +526,7 @@ exports.NaanControllerWeb = function() {
526
526
  statedoc.curversion = kStateCurrentVersion;
527
527
  statedoc.firstver = kStateFirstVersion;
528
528
  statedoc.licensee = "MIT-License";
529
- statedoc.verstring = "1.2.0+1";
529
+ statedoc.verstring = "1.2.1+1";
530
530
  statedoc.date = new Date().toISOString();
531
531
  statedoc.prefs = prefs;
532
532
  statedoc.naan = naanlib.saveState(false); // true to optimize, which is a bit slower
@@ -544,7 +544,7 @@ exports.NaanControllerWeb = function() {
544
544
  || statedoc.firstver > kStateCurrentVersion
545
545
  || statedoc.curversion < kStateFirstVersion
546
546
  || statedoc.licensee != "MIT-License"
547
- || statedoc.verstring != "1.2.0+1")
547
+ || statedoc.verstring != "1.2.1+1")
548
548
  {
549
549
  localStorage.removeItem("NaanState_Hosted");
550
550
  return (false);
@@ -603,7 +603,7 @@ exports.NaanControllerWeb = function() {
603
603
  op: "VsiteOpen",
604
604
  name: vsiteName,
605
605
  naancont: contSelf,
606
- title: vsiteName + " 1.2.0+1"
606
+ title: vsiteName + " 1.2.1+1"
607
607
  });
608
608
  }
609
609
  } catch (e) {
@@ -617,7 +617,7 @@ exports.NaanControllerWeb = function() {
617
617
  op: "VsiteClose",
618
618
  name: vsiteName,
619
619
  naancont: contSelf,
620
- title: vsiteName + " 1.2.0+1"
620
+ title: vsiteName + " 1.2.1+1"
621
621
  });
622
622
  termTextOut("\x1b[90m\x1b[3m".concat("\nwindow closed", "\x1b[0m\n"));
623
623
  }
@@ -632,8 +632,8 @@ exports.NaanControllerWeb = function() {
632
632
  naanlib.banner();
633
633
  var hostpath = naanlib.js.r("path").dirname(window.location.href);
634
634
  naanlib.start({
635
- cmd: 'App.version = "1.2.0+1";;\r\n'
636
- + 'App.cache = "9659b00cb48debdc9726030789336e68";;\r\n'
635
+ cmd: 'App.version = "1.2.1+1";;\r\n'
636
+ + 'App.cache = "f22e60a842b7a65ac309da378d469eed";;\r\n'
637
637
  + 'Naan.module.requireQuery({ naanver: App.cache });;\r\n'
638
638
  + 'Naan.module.webparse("naan_init.nlg", "' + hostpath + '", { naanver: App.cache });;\r\n'
639
639
  });