You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
typesetting/quad/qtest/mds/distributed.md

9.0 KiB

Distributed Places

The racket/place/distributed library provides support for distributed programming.

The example bellow demonstrates how to launch a remote racket node instance, launch remote places on the new remote node instance, and start an event loop that monitors the remote node instance.

The example code can also be found in "racket/distributed/examples/named/master.rkt".

#lang racket/base                                      
(require racket/place/distributed                      
         racket/class                                  
         racket/place                                  
         racket/runtime-path                           
         "bank.rkt"                                    
         "tuple.rkt")                                  
(define-runtime-path bank-path "bank.rkt")             
(define-runtime-path tuple-path "tuple.rkt")           
                                                       
(provide main)                                         
                                                       
(define (main)                                         
  (define remote-node (spawn-remote-racket-node        
                        "localhost"                    
                        #:listen-port 6344))           
  (define tuple-place (supervise-place-at              
                        remote-node                    
                        #:named 'tuple-server          
                        tuple-path                     
                        'make-tuple-server))           
  (define bank-place  (supervise-place-at              
                        remote-node bank-path          
                        'make-bank))                   
                                                       
  (message-router                                      
    remote-node                                        
    (after-seconds 4                                   
      (displayln (bank-new-account bank-place 'user0)) 
      (displayln (bank-add bank-place 'user0 10))      
      (displayln (bank-removeM bank-place 'user0 5)))  
                                                       
    (after-seconds 2                                   
      (define c (connect-to-named-place remote-node    
                                        'tuple-server))
      (define d (connect-to-named-place remote-node    
                                        'tuple-server))
      (tuple-server-hello c)                           
      (tuple-server-hello d)                           
      (displayln (tuple-server-set c "user0" 100))     
      (displayln (tuple-server-set d "user2" 200))     
      (displayln (tuple-server-get c "user0"))         
      (displayln (tuple-server-get d "user2"))         
      (displayln (tuple-server-get d "user0"))         
      (displayln (tuple-server-get c "user2"))         
      )                                                
    (after-seconds 8                                   
      (node-send-exit remote-node))                    
    (after-seconds 10                                  
      (exit 0))))                                      
                                                       

Figure 1: examples/named/master.rkt

The spawn-remote-racket-node primitive connects to "localhost" and starts a racloud node there that listens on port 6344 for further instructions. The handle to the new racloud node is assigned to the remote-node variable. Localhost is used so that the example can be run using only a single machine. However localhost can be replaced by any host with ssh publickey access and racket. The supervise-place-at creates a new place on the remote-node. The new place will be identified in the future by its name symbol 'tuple-server. A place descriptor is expected to be returned by invoking dynamic-place with the tuple-path module path and the 'make-tuple-server symbol.

The code for the tuple-server place exists in the file "tuple.rkt". The "tuple.rkt" file contains the use of define-named-remote-server form, which defines a RPC server suitiable for invocation by supervise-place-at.

#lang racket/base                          
(require racket/match                      
         racket/place/define-remote-server)
                                           
(define-named-remote-server tuple-server   
  (define-state h (make-hash))             
  (define-rpc (set k v)                    
    (hash-set! h k v)                      
    v)                                     
  (define-rpc (get k)                      
    (hash-ref h k #f))                     
  (define-cast (hello)                     
    (printf "Hello from define-cast\n")    
    (flush-output)))                       
                                           

Figure 2: examples/named/tuple.rkt

The define-named-remote-server form takes an identifier and a list of custom expressions as its arguments. From the identifier a place-thunk function is created by prepending the make- prefix. In this case make-tuple-server. The make-tuple-server identifier is the place-function-name given to the supervise-named-dynamic-place-at form above. The define-state custom form translates into a simple define form, which is closed over by the define-rpc form.

The define-rpc form is expanded into two parts. The first part is the client stubs that call the rpc functions. The client function name is formed by concatenating the define-named-remote-server identifier, tuple-server, with the RPC function name set to form tuple-server-set. The RPC client functions take a destination argument which is a remote-connection% descriptor and then the RPC function arguments. The RPC client function sends the RPC function name, set, and the RPC arguments to the destination by calling an internal function named-place-channel-put. The RPC client then calls named-place-channel-get to wait for the RPC response.

The second expansion part of define-rpc is the server implementation of the RPC call. The server is implemented by a match expression inside the make-tuple-server function. The match clause for tuple-server-set matches on messages beginning with the 'set symbol. The server executes the RPC call with the communicated arguments and sends the result back to the RPC client.

The define-cast form is similar to the define-rpc form except there is no reply message from the server to client

(module tuple racket/base                              
  (require racket/place                                
           racket/match)                               
  (define/provide                                      
   (tuple-server-set dest k v)                         
   (named-place-channel-put dest (list 'set k v))      
   (named-place-channel-get dest))                     
  (define/provide                                      
   (tuple-server-get dest k)                           
   (named-place-channel-put dest (list 'get k))        
   (named-place-channel-get dest))                     
  (define/provide                                      
   (tuple-server-hello dest)                           
   (named-place-channel-put dest (list 'hello)))       
  (define/provide                                      
   (make-tuple-server ch)                              
    (let ()                                            
      (define h (make-hash))                           
      (let loop ()                                     
        (define msg (place-channel-get ch))            
        (define (log-to-parent-real                    
                  msg                                  
                  #:severity (severity 'info))         
          (place-channel-put                           
            ch                                         
            (log-message severity msg)))               
        (syntax-parameterize                           
         ((log-to-parent (make-rename-transformer      
                           #'log-to-parent-real)))     
         (match                                        
          msg                                          
          ((list (list 'set k v) src)                  
           (define result (let () (hash-set! h k v) v))
           (place-channel-put src result)              
           (loop))                                     
          ((list (list 'get k) src)                    
           (define result (let () (hash-ref h k #f)))  
           (place-channel-put src result)              
           (loop))                                     
          ((list (list 'hello) src)                    
           (define result                              
             (let ()                                   
               (printf "Hello from define-cast\n")     
               (flush-output)))                        
           (loop))))                                   
        loop))))                                       

Figure 3: Expansion of define-named-remote-server