#102 closed enhancement (fixed)
Improved support for concurrent IPC requests
Reported by: | Jiri Svoboda | Owned by: | |
---|---|---|---|
Priority: | major | Milestone: | 0.4.3 |
Component: | helenos/lib/c | Version: | mainline |
Keywords: | Cc: | jakub@… | |
Blocker for: | Depends on: | ||
See also: |
Description
Currently it is difficult to handle requests from one client to one server concurrently. This not only hurts parallelism, but it can lead to deadlocks and difficult-to-solve problems. Ad-hoc solving with pending requests is cumbersome.
For the purpose of concurrent requests it is useful to establish notion of two objects:
- transaction is a sequence of related IPC requests and responses (similar to a SCSI exchange)
- relation is a logical data path between a client and a server
In current code the grouping of requests/response pairs into transactions is mostly implicit. Requests and responses are paired by the kernel. A transaction often consists of sending more than one request (one with user method, other with method such as M_READ, M_WRITE, etc.) and finally waiting for all the responses In this situation concurrent requests occurring at the same phone line can be separated as long as the requests of two transactions do not intermix (responses can happen anytime, because they can be always paired with requests).
What we cannot do is allow delays between requests in a transaction or allow transactions consisting of several consecutive 'send request-wait response' cycles.
Even in the current situation, separating transactions and routing requests to appropriate fibrils can be difficult. Thus, we propose extending the async API so that the transaction to which a request belongs can be specified explicitly. The relation object is need to represent the frameworks idea of a logical connection to the server.
To sum up, the application would first create a relation to a server, start and terminate transactions on the relation, and issue requests within a transaction.
There are different possible implementation of this functionality. The currently proposed one is to use multiple physical connections (phones) for each relation, as many as there are concurrent transactions. The phones would not be hanged up immediately after finishing a transaction, but rather kept around for later use. On the server side there would be simply one fibril per connection.
The advantage of this solution is simplicity of routing, the disadvantage is the possible wasting of kernel resources (phones) if the number of concurrent transactions in tasks is bursty.
An alternative implementation proposal was to use a single phone and demux the transactions in the server's async framework. However, this would probably require sending a transaction ID with each request, which could be costly and difficult.
Change History (5)
comment:1 by , 14 years ago
comment:2 by , 14 years ago
Cc: | added |
---|
comment:3 by , 14 years ago
Resolution: | → fixed |
---|---|
Status: | new → closed |
Fixed in changeset:mainline,629.
comment:4 by , 14 years ago
I have no idea what I was thinking of but obviously the proper English translation for the Czech term 'relace' is 'session'. I fixed this as of changeset:mainline,771. Also I replaced 'transaction' with 'exchange' (term inspired by Fibre Channel standards). It is shorter and it does not make a false pretence of having any sort of ACID semantics.
I also improved the API to use explicit session setup and teardown. This allows properly releasing resources (closing connections) when a session is destroyed. It also brings us a step closer to the fully abstract session API.
With the current API, it is still not possible to implement sessions using virtual paths (instead of parallel physical connections). For this we need async operations that work with exchanges instead of plain phone IDs.
comment:5 by , 14 years ago
Type: | proposal → enhancement |
---|
After one failed trial attempt to come up with an API according to your proposal, I realized that perhaps the easiest, most straightforward and still generic-enough way would be to explicitly state that relations are still represented by phones. This would allow us to add:
to begin and end a relation and use the already existing async API for everything else, i.e. the IPC communication itself. Otherwise we would have to add another transactional layer, duplicate many interfaces and rewrite a lot of [VFS] code to use those interfaces.
Generic-enough means that by using phones as keys to identify the connection for which to start the relation, we are not losing anything since representing a connection between two tasks is what phones already do.
On the other hand, using phones to represent relations was one way considered, so if this makes it possible to use the already existing async code for making transactions, why not do so openly and explicitly? Phone ID is an ID just as any other ID. In this regard, phones are similar and could be compared with file handles, which are used for many various things in Unix.
The two functions I am proposing above would take care of all the necessary bookkeeping, which includes caching open relation phones, opening new relation phones as necessary, waiting for some relation phones to become available and/or stealing some cached but unused relation phones if new relation phones cannot be allocated.