Skip to content

Commit

Permalink
add implementation section to design
Browse files Browse the repository at this point in the history
  • Loading branch information
jreadey committed Oct 14, 2024
1 parent 1be825e commit 7a3b243
Showing 1 changed file with 67 additions and 1 deletion.
68 changes: 67 additions & 1 deletion docs/design/map/h5_map.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,4 +142,70 @@ RETURN: HTTP Status code. 404 if key does not exist

## 2. Design/Architecture

TBD
The datatype for a map object will be a numpy dtype compound of the datatypes for the key and value.

Map object data will be stored as binary images of numpy arrays with the above type (similar to how dataset
chunks are stored currently). Since the data will be mostly sparse, it will make sense for some type of compression to be
used by default. Data will be chunked with 2-4 MiB chunk sizes. Number of chunks will automatically increase as keys are added
to the map.

### Control Flow for PUT operations

On write (PUT with key and value), the SN will get a list of allocated chunks (for performance reasons it will be useful to keep a
cache of chunk ids and only update as chunks are added to the map). If no chunk has been allocated (e.g. first write to the map),
a chunk id will be allocated.

For each chunk_id, the SN will do a PUT to the DN that owns that chunk id while a 507 (no storage) status is returned (see below).
If a 507 is returned for each chunk id, a new chunk id will be allocated, and the request sent to the DN that owns that chunk.
Finally the status (200, 201, or 410) will be returned to the client.

For the DN, when a PUT request is received, it will first fetch the chunk. If the chunk is not found (i.e. this is the
first write to the chunk), the DN will create a new numpy array in memory. Next the key will be hashed and the result used to
find the row for the given chunk.

The next step depends on the existing state of the row:

* The row is empty, the unhashed key and value will be written to the row. The chunk is then marked dirty to be lazily written to storage
* The row is occupied and the key value is different from the incoming key, the DN returns a 507 (Storage unavailable) to the SN
* The row is occupied and the key value is the same as the incoming key and the value is the same as the incoming value, the DN returns 200
* The row is occupied and the key value is the same, while the value is different, the DN returns 409 (Conflict to the SN)

### Control flow for GET operations

On read (GET with key), the SN will get a lst of allocated chunks. The SN will then send async requests to each DN that owns one or more
chunks with the chunks ids and key. If any DN returns 200, then the value returned by the DN will be returned to the client. If all DNs return 404 (Not Found), a 404 will be returned the client.

For the DN, for each chunkid the chunk will be fetched, and the key hash will be used to determine which row in the chunk should be examined.

As with PUT, the next step depends on the existing state of the row:

* The row is empty, a 404 is returned
* The row is occupied and the key value is different from the incoming key, a 404 is returned
* The row is occupied and the key value is the same as the incoming key the value for the row is returned with a 200 response

### Control flow for DELETE operations

On remove operations (DELETE with a key), the SN will get a list of allocated chunks. The DN will then send async delete requests to each DN that owns one or more chunks. If any DN returns 200, then a 200 will be returned to the client. If all DNS return a 404, then a 404 will be returned to the client. (TBD: support 410, Gone responses).


For the DN, for each chunkid the chunk will be fetched, and the key hash will be used to determine which row in the chunk should be examind.

Again the next step depends on the existing state of the row:

* The row is empty, a 404 is returned
* The row is occupied and the key value is different from the incoming key, a 404 is returned
* The row is occupied and the key value is the same as the incoming key, the row is zero'd out (making it available for new writes). A 200 response is returned

If after a deletion, all the rows in a chunk are empty, the chunk will be deleted.

## Performance and storage considerations

Given latency involved in server requests, it will be much more efficient to read or write multiple keys in one request.

As the number of chunks increases, all DNs will see an increase in CPU load (and throughput if the chunks are not already cached in memory). SN latency should not increase as much as all DN are searching the chunks in parallel.

Write operations are more sensitive to increases in the number of chunks since each chunk much be searched sequentially till an
open slot is found.

The number of chunks vs the number of keys will be determined by the chunk size and frequency of hash collisions.
Assuming compression is used, the total storage size will be linearly porpotional the number of keys.

0 comments on commit 7a3b243

Please sign in to comment.