dist.scm 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. ;;; dist.scm -- Spirit of disrtibuted computing for Scheme.
  2. ;; Copyright (C) 2014, 2015, 2016, 2017 Artyom V. Poptsov <poptsov.artyom@gmail.com>
  3. ;;
  4. ;; This file is a part of Guile-SSH.
  5. ;;
  6. ;; Guile-SSH is free software: you can redistribute it and/or
  7. ;; modify it under the terms of the GNU General Public License as
  8. ;; published by the Free Software Foundation, either version 3 of the
  9. ;; License, or (at your option) any later version.
  10. ;;
  11. ;; Guile-SSH is distributed in the hope that it will be useful, but
  12. ;; WITHOUT ANY WARRANTY; without even the implied warranty of
  13. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. ;; General Public License for more details.
  15. ;;
  16. ;; You should have received a copy of the GNU General Public License
  17. ;; along with Guile-SSH. If not, see
  18. ;; <http://www.gnu.org/licenses/>.
  19. ;;; Commentary:
  20. ;; This module contains distributed forms of some useful procedures such as
  21. ;; 'map'.
  22. ;;
  23. ;; The module exports:
  24. ;; distribute
  25. ;; dist-map
  26. ;; with-ssh
  27. ;; rrepl
  28. ;; make-node
  29. ;; node?
  30. ;; node-session
  31. ;; node-rrepl-port
  32. ;;
  33. ;; See the Info documentation for the detailed description of these
  34. ;; procedures.
  35. ;;; Code:
  36. (define-module (ssh dist)
  37. #:use-module (ice-9 rdelim)
  38. #:use-module (ice-9 receive)
  39. #:use-module (ice-9 threads)
  40. #:use-module (srfi srfi-1)
  41. #:use-module (srfi srfi-26)
  42. #:use-module (ssh session)
  43. #:use-module (ssh channel)
  44. #:use-module (ssh dist node)
  45. #:use-module (ssh dist job)
  46. #:re-export (node? node-session node-rrepl-port make-node with-ssh)
  47. #:export (distribute dist-map rrepl))
  48. ;;; Helper procedures
  49. (define (flatten-1 lst)
  50. "Flatten a list LST one level down. Return a flattened list."
  51. (fold-right append '() lst))
  52. (define (format-warning fmt . args)
  53. (apply format (current-error-port) (string-append "WARNING: " fmt) args))
  54. (define (format-error fmt . args)
  55. (apply format (current-error-port) (string-append "ERROR: " fmt) args))
  56. (define (execute-job nodes job)
  57. "Execute a JOB, handle errors."
  58. (catch 'node-error
  59. (lambda ()
  60. (catch 'node-repl-error
  61. (lambda ()
  62. (hand-out-job job))
  63. (lambda args
  64. (format-error "In ~a:~%~a:~%~a~%" job (cadr args) (caddr args))
  65. (error "Could not execute a job" job))))
  66. (lambda args
  67. (format-warning "Could not execute a job ~a~%" job)
  68. (let ((nodes (delete (job-node job) nodes)))
  69. (when (null? nodes)
  70. (error "Could not execute a job" job))
  71. (format-warning "Passing a job ~a to a node ~a ...~%" job (car nodes))
  72. (execute-job nodes (set-job-node job (car nodes)))))))
  73. (define (execute-jobs nodes jobs)
  74. "Execute JOBS on NODES, return the result."
  75. (flatten-1 (n-par-map (length jobs) (cut execute-job nodes <>) jobs)))
  76. ;;;
  77. (define-syntax-rule (distribute nodes expr ...)
  78. "Evaluate each EXPR in parallel, using distributed computation. Split the
  79. job to nearly equal parts and hand out each of resulting sub-jobs to a NODES
  80. list. Return the results of N expressions as a set of N multiple values."
  81. (let* ((jobs (assign-eval nodes (list (quote expr) ...)))
  82. (results (execute-jobs nodes jobs)))
  83. (when (null? results)
  84. (error "Could not execute jobs" nodes jobs))
  85. (apply values results)))
  86. (define-syntax-rule (dist-map nodes proc lst)
  87. "Do list mapping using distributed computation. The job is splitted to
  88. nearly equal parts and hand out resulting jobs to a NODES list. Return the
  89. result of computation."
  90. (let* ((jobs (assign-map nodes lst (quote proc)))
  91. (results (execute-jobs nodes jobs)))
  92. (when (null? results)
  93. (error "Could not execute jobs" nodes jobs))
  94. results))
  95. (define (rrepl node)
  96. "Start an interactive remote REPL (RREPL) session using NODE."
  97. (let ((repl-channel (node-open-rrepl node)))
  98. (while (channel-open? repl-channel)
  99. (cond
  100. ((and (channel-open? repl-channel) (char-ready? repl-channel))
  101. (display (read-char repl-channel)))
  102. ((and (channel-open? repl-channel) (char-ready? (current-input-port)))
  103. (display (read-char (current-input-port)) repl-channel))
  104. (else
  105. (usleep 5000))))))
  106. ;;; dist.scm ends here