# Parallelism Generating a Single HTTP Response

Using Fork-Join (FJ) parallelism a conventional 
HTTP server can use multiple cores to generate
a single a response by forking threads
when a request is received, generating the response in
parallel, joining all the threads when the work is complete,
and then returning the response from the original single thread.

HTTP applications frequently require state to persist between requests,
this example uses the URL path as a session ID that can be used to
persist state between requests.  Each request itself may include
one or more fork-join parallel regions.

## Parallel Web Server Architecture

This example combines Node.js' built-in HTTP server module
with EMS for shared memory and task level parallelism.

When the server is started it allocates a globally shared
EMS shared memory (`serverState.ems`) that exists until the server exits.
The global shared memory is used for diagnostic counters like the 
number of queries as well as key-value pairs that can be read
or written from a parallel or serial region of any request or session.

<img src="http://synsem.com/images/ems/parWebServer.svg" type="image/svg+xml">

## REST API

A valid request URL consists of path naming the session ID
and a query that specifies if the session is new/restarting, or
is a continuation of a previous session.
 
__REST API:__  `/sessionID?<old|new>&<keep|free>`
 
- `sessionID` - An unique session identifier.  The shared memory
  persistent file will be named `session.sessionID.ems` and stored
  in the current working directory.

- `?<old|new>` - A `new` session will remove an existing
  session-private shared memory if present, an `old` session
  will attach to a previously created shared memory that was
  persisted to disk.
  
- `?<keep|free>` - Release or preserve, respectively, the 
  session's shared memory at the end of the request.


## Fork-Join Parallelism

A process using Fork-Join parallelism starts single-threaded,
creating parallel regions when needed, then returning to
single-threaded execution when all the threads in the 
parallel region have completed execution.
EMS amortizes the cost of starting new processes by using a thread pool
where idle threads can quickly be restarted when they are needed again.

By way of comparison, all the processes in Bulk Synchronous Parallelism
are always executing, barriers can be used to synchronize execution.

<table>
  <tr>
    <td>
      <center>
      Fork-Join Parallelism<br>
      <img src="http://synsem.com/images/ems/tasksAndLoopsFJ.svg" type="image/svg+xml" height="360px">
      </center>
    </td>
    <td>
      <center>
      Bulk Synchronous Parallelism<br>
      <img src="http://synsem.com/images/ems/tasksAndLoopsBSP.svg" type="image/svg+xml" height="360px">
      </center>
    </td>
  </tr>
</table>


## Web Server Process

The web server is a conventional single-threaded based on Node.js'
built-in HTTP module.  As part of the single-threaded initialization
EMS is initialized for Fork-Join parallelism and a shared memory
is created for the processes to share diagnostic counters and other
common state.  This shared memory lasts for the life of the web
server process and does not persist between invocations of the server.

When a request is received, the URL is parsed, then the server enters
a parallel region.  From the parallel region each process creates or
attaches to shared memory created 





## Example
Start the server:
`node webServer.js [# of processes, default=8]`

From another terminal or browser, issue requests to the server.

A parallel region is created for each request received by the web server,
handling the single request with multiple processes.
Different variables in the response are used to illustrate
different types of data updates.

- `requestN` - Every request is given an unique ID
- `sessionData` - Each process records it's "work" in the private EMS
   memory allocated for the session (`foo` or `bar`).  
   The results in the form
  `(Req:<Request Number>/<EMS ProcessID>)`, the processes may complete
  in any order, but each request is handled sequentially.
- `bignum` - The sum of a loop incrementing a counter in session
  private EMS memory
- `randomSum` - The sum of random numbers generated by all the processes,
  stored in the shared global EMS memory 
  
Following the join at the end of the parallel region,
  single-threaded execution continues, copying the different
  variables into a response object  


```
dunlin> curl 'http://localhost:8080/foo?new&keep'  # Create a new persistent memory for session "foo"
{"requestN":0,"sessionData":"0(Req:0/2) (Req:0/7) (Req:0/1) (Req:0/4) (Req:0/5) (Req:0/3) (Req:0/0) (Req:0/6) ","bignum":100000,"randomSum":6103}

dunlin> curl 'http://localhost:8080/foo?old&keep'  # Modify the existing "foo" memory
{"requestN":1,"sessionData":"0(Req:0/2) (Req:0/7) (Req:0/1) (Req:0/4) (Req:0/5) (Req:0/3) (Req:0/0) (Req:0/6) (Req:1/0) (Req:1/4) (Req:1/1) (Req:1/3) (Req:1/5) (Req:1/7) (Req:1/6) (Req:1/2) ","bignum":200000,"randomSum":16670}

dunlin> curl 'http://localhost:8080/bar?old'  # Error because "bar" does not yet exist, 'keep' implied
ERROR: Requested "old" shared memory bar does not already exist.

dunlin> curl 'http://localhost:8080/bar?new&free'  # Create and free session memory "bar"
{"requestN":3,"sessionData":"0(Req:3/4) (Req:3/7) (Req:3/5) (Req:3/3) (Req:3/0) (Req:3/6) (Req:3/2) (Req:3/1) ","bignum":100000,"randomSum":25530}

dunlin> curl 'http://localhost:8080/foo?old&keep'  # Modify the existing "foo" memory again
{"requestN":4,"sessionData":"0(Req:0/2) (Req:0/7) (Req:0/1) (Req:0/4) (Req:0/5) (Req:0/3) (Req:0/0) (Req:0/6) (Req:1/0) (Req:1/4) (Req:1/1) (Req:1/3) (Req:1/5) (Req:1/7) (Req:1/6) (Req:1/2) (Req:4/0) (Req:4/5) (Req:4/2) (Req:4/7) (Req:4/6) (Req:4/1) (Req:4/3) (Req:4/4) ","bignum":300000,"randomSum":30114}

dunlin> curl 'http://localhost:8080/foo?new&free'  # Modify the existing "foo" memory again, this time freeing it
{"requestN":5,"sessionData":"0(Req:5/4) (Req:5/7) (Req:5/5) (Req:5/0) (Req:5/2) (Req:5/6) (Req:5/1) (Req:5/3) ","bignum":100000,"randomSum":36887}

dunlin> curl 'http://localhost:8080/foo?old&free'  # The memory "foo" has been released
ERROR: Requested "old" shared memory foo does not already exist.
```


###### Copyright (C)2017 Jace A Mogill - All Rights Reserved.
