Sophie

Sophie

distrib > Mandriva > 2008.1 > x86_64 > by-pkgid > 535a7a10fe62254ee9ca7e6375f081a9 > files > 401

ocaml-ocamlnet-2.2.7-4mdv2008.1.x86_64.rpm

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<link rel="stylesheet" href="style.css" type="text/css">
<meta content="text/html; charset=iso-8859-1" http-equiv="Content-Type">
<link rel="Start" href="index.html">
<link rel="previous" href="Netshm_array.html">
<link rel="next" href="Netconversion.html">
<link rel="Up" href="index.html">
<link title="Index of types" rel=Appendix href="index_types.html">
<link title="Index of exceptions" rel=Appendix href="index_exceptions.html">
<link title="Index of values" rel=Appendix href="index_values.html">
<link title="Index of class attributes" rel=Appendix href="index_attributes.html">
<link title="Index of class methods" rel=Appendix href="index_methods.html">
<link title="Index of classes" rel=Appendix href="index_classes.html">
<link title="Index of class types" rel=Appendix href="index_class_types.html">
<link title="Index of modules" rel=Appendix href="index_modules.html">
<link title="Index of module types" rel=Appendix href="index_module_types.html">
<link title="Uq_gtk" rel="Chapter" href="Uq_gtk.html">
<link title="Equeue" rel="Chapter" href="Equeue.html">
<link title="Unixqueue" rel="Chapter" href="Unixqueue.html">
<link title="Uq_engines" rel="Chapter" href="Uq_engines.html">
<link title="Uq_socks5" rel="Chapter" href="Uq_socks5.html">
<link title="Unixqueue_mt" rel="Chapter" href="Unixqueue_mt.html">
<link title="Equeue_intro" rel="Chapter" href="Equeue_intro.html">
<link title="Uq_ssl" rel="Chapter" href="Uq_ssl.html">
<link title="Uq_tcl" rel="Chapter" href="Uq_tcl.html">
<link title="Netcgi_common" rel="Chapter" href="Netcgi_common.html">
<link title="Netcgi" rel="Chapter" href="Netcgi.html">
<link title="Netcgi_ajp" rel="Chapter" href="Netcgi_ajp.html">
<link title="Netcgi_scgi" rel="Chapter" href="Netcgi_scgi.html">
<link title="Netcgi_cgi" rel="Chapter" href="Netcgi_cgi.html">
<link title="Netcgi_fcgi" rel="Chapter" href="Netcgi_fcgi.html">
<link title="Netcgi_dbi" rel="Chapter" href="Netcgi_dbi.html">
<link title="Netcgi1_compat" rel="Chapter" href="Netcgi1_compat.html">
<link title="Netcgi_test" rel="Chapter" href="Netcgi_test.html">
<link title="Netcgi_porting" rel="Chapter" href="Netcgi_porting.html">
<link title="Netcgi_plex" rel="Chapter" href="Netcgi_plex.html">
<link title="Http_client" rel="Chapter" href="Http_client.html">
<link title="Telnet_client" rel="Chapter" href="Telnet_client.html">
<link title="Ftp_data_endpoint" rel="Chapter" href="Ftp_data_endpoint.html">
<link title="Ftp_client" rel="Chapter" href="Ftp_client.html">
<link title="Nethttpd_types" rel="Chapter" href="Nethttpd_types.html">
<link title="Nethttpd_kernel" rel="Chapter" href="Nethttpd_kernel.html">
<link title="Nethttpd_reactor" rel="Chapter" href="Nethttpd_reactor.html">
<link title="Nethttpd_engine" rel="Chapter" href="Nethttpd_engine.html">
<link title="Nethttpd_services" rel="Chapter" href="Nethttpd_services.html">
<link title="Nethttpd_plex" rel="Chapter" href="Nethttpd_plex.html">
<link title="Nethttpd_intro" rel="Chapter" href="Nethttpd_intro.html">
<link title="Netplex_types" rel="Chapter" href="Netplex_types.html">
<link title="Netplex_mp" rel="Chapter" href="Netplex_mp.html">
<link title="Netplex_mt" rel="Chapter" href="Netplex_mt.html">
<link title="Netplex_log" rel="Chapter" href="Netplex_log.html">
<link title="Netplex_controller" rel="Chapter" href="Netplex_controller.html">
<link title="Netplex_container" rel="Chapter" href="Netplex_container.html">
<link title="Netplex_sockserv" rel="Chapter" href="Netplex_sockserv.html">
<link title="Netplex_workload" rel="Chapter" href="Netplex_workload.html">
<link title="Netplex_main" rel="Chapter" href="Netplex_main.html">
<link title="Netplex_config" rel="Chapter" href="Netplex_config.html">
<link title="Netplex_kit" rel="Chapter" href="Netplex_kit.html">
<link title="Rpc_netplex" rel="Chapter" href="Rpc_netplex.html">
<link title="Netplex_cenv" rel="Chapter" href="Netplex_cenv.html">
<link title="Netplex_intro" rel="Chapter" href="Netplex_intro.html">
<link title="Netshm" rel="Chapter" href="Netshm.html">
<link title="Netshm_data" rel="Chapter" href="Netshm_data.html">
<link title="Netshm_hashtbl" rel="Chapter" href="Netshm_hashtbl.html">
<link title="Netshm_array" rel="Chapter" href="Netshm_array.html">
<link title="Netshm_intro" rel="Chapter" href="Netshm_intro.html">
<link title="Netconversion" rel="Chapter" href="Netconversion.html">
<link title="Netchannels" rel="Chapter" href="Netchannels.html">
<link title="Netstream" rel="Chapter" href="Netstream.html">
<link title="Mimestring" rel="Chapter" href="Mimestring.html">
<link title="Netmime" rel="Chapter" href="Netmime.html">
<link title="Netsendmail" rel="Chapter" href="Netsendmail.html">
<link title="Neturl" rel="Chapter" href="Neturl.html">
<link title="Netaddress" rel="Chapter" href="Netaddress.html">
<link title="Netbuffer" rel="Chapter" href="Netbuffer.html">
<link title="Netdate" rel="Chapter" href="Netdate.html">
<link title="Netencoding" rel="Chapter" href="Netencoding.html">
<link title="Netulex" rel="Chapter" href="Netulex.html">
<link title="Netaccel" rel="Chapter" href="Netaccel.html">
<link title="Netaccel_link" rel="Chapter" href="Netaccel_link.html">
<link title="Nethtml" rel="Chapter" href="Nethtml.html">
<link title="Netstring_str" rel="Chapter" href="Netstring_str.html">
<link title="Netstring_pcre" rel="Chapter" href="Netstring_pcre.html">
<link title="Netstring_mt" rel="Chapter" href="Netstring_mt.html">
<link title="Netmappings" rel="Chapter" href="Netmappings.html">
<link title="Netaux" rel="Chapter" href="Netaux.html">
<link title="Nethttp" rel="Chapter" href="Nethttp.html">
<link title="Netchannels_tut" rel="Chapter" href="Netchannels_tut.html">
<link title="Netmime_tut" rel="Chapter" href="Netmime_tut.html">
<link title="Netsendmail_tut" rel="Chapter" href="Netsendmail_tut.html">
<link title="Netulex_tut" rel="Chapter" href="Netulex_tut.html">
<link title="Neturl_tut" rel="Chapter" href="Neturl_tut.html">
<link title="Netsys" rel="Chapter" href="Netsys.html">
<link title="Netpop" rel="Chapter" href="Netpop.html">
<link title="Rpc_auth_dh" rel="Chapter" href="Rpc_auth_dh.html">
<link title="Rpc_key_service" rel="Chapter" href="Rpc_key_service.html">
<link title="Rpc_time" rel="Chapter" href="Rpc_time.html">
<link title="Rpc_auth_local" rel="Chapter" href="Rpc_auth_local.html">
<link title="Rtypes" rel="Chapter" href="Rtypes.html">
<link title="Xdr" rel="Chapter" href="Xdr.html">
<link title="Rpc" rel="Chapter" href="Rpc.html">
<link title="Rpc_program" rel="Chapter" href="Rpc_program.html">
<link title="Rpc_portmapper_aux" rel="Chapter" href="Rpc_portmapper_aux.html">
<link title="Rpc_packer" rel="Chapter" href="Rpc_packer.html">
<link title="Rpc_transport" rel="Chapter" href="Rpc_transport.html">
<link title="Rpc_client" rel="Chapter" href="Rpc_client.html">
<link title="Rpc_simple_client" rel="Chapter" href="Rpc_simple_client.html">
<link title="Rpc_portmapper_clnt" rel="Chapter" href="Rpc_portmapper_clnt.html">
<link title="Rpc_portmapper" rel="Chapter" href="Rpc_portmapper.html">
<link title="Rpc_server" rel="Chapter" href="Rpc_server.html">
<link title="Rpc_auth_sys" rel="Chapter" href="Rpc_auth_sys.html">
<link title="Rpc_intro" rel="Chapter" href="Rpc_intro.html">
<link title="Rpc_mapping_ref" rel="Chapter" href="Rpc_mapping_ref.html">
<link title="Rpc_ssl" rel="Chapter" href="Rpc_ssl.html">
<link title="Rpc_xti_client" rel="Chapter" href="Rpc_xti_client.html">
<link title="Shell_sys" rel="Chapter" href="Shell_sys.html">
<link title="Shell" rel="Chapter" href="Shell.html">
<link title="Shell_uq" rel="Chapter" href="Shell_uq.html">
<link title="Shell_mt" rel="Chapter" href="Shell_mt.html">
<link title="Shell_intro" rel="Chapter" href="Shell_intro.html">
<link title="Netsmtp" rel="Chapter" href="Netsmtp.html"><link title="Shared Memory for IPC" rel="Section" href="#1_SharedMemoryforIPC">
<link title="What kind of shared memory we talk about" rel="Subsection" href="#2_Whatkindofsharedmemorywetalkabout">
<link title="Types of shared memory provided by the OS" rel="Subsection" href="#2_TypesofsharedmemoryprovidedbytheOS">
<link title="Global names" rel="Subsection" href="#2_Globalnames">
<link title="Opening shared memory objects" rel="Subsection" href="#2_Openingsharedmemoryobjects">
<link title="Data structures" rel="Subsection" href="#2_Datastructures">
<link title="Concurrent Access" rel="Subsection" href="#2_ConcurrentAccess">
<link title="Grouping" rel="Subsection" href="#2_Grouping">
<link title="Applications" rel="Subsection" href="#2_Applications">
<link title="Limits" rel="Subsection" href="#2_Limits">
<title>Ocamlnet 2 Reference Manual : Netshm_intro</title>
</head>
<body>
<div class="navbar"><a href="Netshm_array.html">Previous</a>
&nbsp;<a href="index.html">Up</a>
&nbsp;<a href="Netconversion.html">Next</a>
</div>
<center><h1>Netshm_intro</h1></center>
<br>
<br>
<a name="1_SharedMemoryforIPC"></a>
<h1>Shared Memory for IPC</h1>
<p>

The <code class="code">netshm</code> library implements a number of practical schemes to manage
shared memory. Here we give a tutorial how to use that functions.
<p>

<a name="2_Whatkindofsharedmemorywetalkabout"></a>
<h2>What kind of shared memory we talk about</h2>
<p>

In general, shared memory is a memory region that is mapped into several
address spaces. The O'Caml language already supports one kind of shared
memory out of the box, the so-called multi-threading. Here, several
execution threads access the same memory, and thus can access the same
data. There are a lot of accompanying techniques allowing one to manage
shared memory (mutexes, condition variables, event channels, etc.).
<p>

Of course, the <code class="code">netshm</code> library does not use this kind of shared
memory (it is effectively even incompatible with multi-threading to
some degree). Here, memory is shared by independent processes. This
means that any process on the computer can access a shared memory
object provided
<p>
<ul>
<li>the process knows the global name of the object, and</li>
<li>the process has the access rights.</li>
</ul>

It is not necessary that the processes have something else in common
(e.g. that one process is created by the other, etc.).
<p>

<a name="2_TypesofsharedmemoryprovidedbytheOS"></a>
<h2>Types of shared memory provided by the OS</h2>
<p>

In the Unix world, there are (at least) two common APIs to access
global shared memory objects:
<p>
<ul>
<li>System V shared memory</li>
<li>POSIX shared memory</li>
</ul>

The <code class="code">netshm</code> library has an extensible interface that can support
several system APIs. Currently, however, there is only an
implementation for POSIX shared memory.
<p>

In addition to that, it is also possible to access file-backed memory.
<p>

Note that not all OS support POSIX shared memory. To check, look at
the value of <code class="code">Netsys.have_posix_shm()</code>.
<p>

<a name="2_Globalnames"></a>
<h2>Global names</h2>
<p>

The module <a href="Netshm.html"><code class="code">Netshm</code></a> defines the possible global names:
<p>

<pre><code class="code"> 
type shm_name =
  [ `POSIX of string
  | `File of string
  ]
</code></pre>
<p>

For POSIX shared memory you must take a <code class="code">`POSIX</code> global name, for
file-backed memory a <code class="code">`File</code> name. A <code class="code">`POSIX</code> global name has 
a string as argument that looks like a strange file name. It must
begin with a slash, followed by the name that must not contain 
further slashes, e.g. <code class="code">`POSIX "/sample"</code>.
<p>

Actually, the OS transforms this name to a real filename in a
system-dependent way. For example, Linux would map <code class="code">`POSIX "/sample"</code>
to the real file <code class="code">/dev/shm/sample</code>. There is, however, no way to
find something out about this transformation from a portable
program.
<p>

The <code class="code">`File</code> names are real file names.
<p>

<a name="2_Openingsharedmemoryobjects"></a>
<h2>Opening shared memory objects</h2>
<p>

There is the function <a href="Netshm.html#VALopen_shm"><code class="code">Netshm.open_shm</code></a> that works much like
<code class="code">Unix.openfile</code>. For example,
<p>

<pre><code class="code">let sd = 
  Netshm.open_shm (`POSIX "/sample") [Unix.O_CREAT; Unix.O_RDWR] 0o666
</code></pre>
<p>

opens <code class="code">/sample</code> for read-write access, and if the object does not
exist yet, it is created with mode 0o666. The returned result
is a so-called shared memory descriptor.
<p>

In order to create unique new objects, you can also use
<a href="Netshm.html#VALcreate_unique_shm"><code class="code">Netshm.create_unique_shm</code></a>. This function takes a pattern for the
global name, and creates a new object with a unique name based on the
pattern. This is done by replacing all <code class="code">'X'</code> letters in the string
argument by random characters until a new name has been found.
For example:
<p>

<pre><code class="code">let sd =
  Netshm.create_unique_shm (`POSIX "/myprogram.XXXXX") 0o666
</code></pre>
<p>

The actual name is returned by <a href="Netshm.html#VALname_of_shm"><code class="code">Netshm.name_of_shm</code></a>.
<p>

Like files, shared memory objects must be closed after usage:
<p>

<pre><code class="code">Netshm.close_shm sd
</code></pre>
<p>

Of course, the object continues to exist after the descriptor
has been closed. There is a special function <a href="Netshm.html#VALunlink_shm"><code class="code">Netshm.unlink_shm</code></a>
to delete objects.
<p>

It is discouraged to open shared memory objects several times in
parallel from the same process, as locking methods (see below) are
confused by this.
<p>

<a name="2_Datastructures"></a>
<h2>Data structures</h2>
<p>

The <a href="Netshm.html"><code class="code">Netshm</code></a> module contains only the algorithms for the primitve
data structure, a hash table from <code class="code">int32</code> to bigarrays of
<code class="code">int32</code> elements. <a href="Netshm_hashtbl.html"><code class="code">Netshm_hashtbl</code></a> and <a href="Netshm_array.html"><code class="code">Netshm_array</code></a> have 
user-friendlier data structures:
<p>
<ul>
<li><a href="Netshm_hashtbl.html"><code class="code">Netshm_hashtbl</code></a> is a hash table from type s to t, where
  both s and t can be any so-called manageable type (see below).</li>
<li><a href="Netshm_array.html"><code class="code">Netshm_array</code></a> is an array of elements, again of one of
  the mentioned manageable types. Arrays can be sparse.</li>
</ul>

The element types are restricted to those types that can be
managed with <a href="Netshm_data.html"><code class="code">Netshm_data</code></a>. In principle, this can be any
type for which you can write a data manager.
<a href="Netshm_data.html"><code class="code">Netshm_data</code></a> contains only data managers for these types:
<p>
<ul>
<li><code class="code">int</code></li>
<li><code class="code">int32</code></li>
<li><code class="code">int64</code></li>
<li><code class="code">nativeint</code></li>
<li><code class="code">string</code></li>
<li>pairs of two manageable types (pairs of pairs are allowed)</li>
</ul>

For example, to get a data manager for the pair of an <code class="code">int</code>
and a <code class="code">string</code>, one can do
<p>

<pre><code class="code"> let dm =
      Netshm_data.pair_manager
         Netshm_data.int_manager
         Netshm_data.string_manager
</code></pre>
<p>

<code class="code">dm</code> has then type <code class="code">(int * string) data_manager</code>.
<p>

In order to view a shared memory object as hash table or array,
it is necessary to <code class="code">manage</code> it:
<p>

<pre><code class="code"> 
  let sd = 
    Netshm.open_shm (`POSIX "/sample") [Unix.O_RDWR] 0 in
  let tab =
    Netshm_hashtbl.manage
      Netshm_data.string_manager
      dm
      `No_locking
      sd
</code></pre>
<p>

The <code class="code">manage</code> function for hash tables takes the data managers for
keys and values of the table, a thing called <code class="code">`No_locking</code>, and
the shared memory descriptor <code class="code">sd</code> as input. It returns the
abstract value that represents the hash table. What <code class="code">`No_locking</code>
means will become clearer below.
<p>

After being managed, you can access <code class="code">tab</code> like a hash table:
<p>

<pre><code class="code">  Netshm_hashtbl.add tab "First Key" (1, "First value")

  let (n, s) = Netshm_hashtbl.find tab "First Key"
</code></pre>
<p>

Note that neither input nor output values of managed objects are
placed in shared memory. They are normal O'Caml values for which no
restrictions apply. The shared memory is totally hidden from user code
(actually, there are two functions in <a href="Netshm.html"><code class="code">Netshm</code></a> that exhibit values
that reside in this memory, but they should only be used by experts).
<p>

The <code class="code">manage</code> function for arrays is slightly different. In particular,
only one data manager must be given.
<p>

<a name="2_ConcurrentAccess"></a>
<h2>Concurrent Access</h2>
<p>

If <code class="code">`No_locking</code> is effective, nothing is done by netshm to make
concurrent accesses by several processes to the same object safe.  The
implications depend on what you do. If you only read, everything is
ok. If there is a writer, it is possible that netshm cannot access
the object properly in certain situations, and it is even possible 
that the internal structures of the object are destroyed.
<p>

In order to avoid such problems, you can specify a locking method
other than <code class="code">`No_locking</code>. Currently there is only <code class="code">`Record_locking</code>.
<p>

It is sufficient to pass <code class="code">`Record_locking</code> to the <code class="code">manage</code> 
functions - the rest works automatically:
<p>

<pre><code class="code">  let tab =
    Netshm_hashtbl.manage
      Netshm_data.string_manager
      dm
      `Record_locking
      sd
</code></pre>
<p>

Record locking bases on the <code class="code">Unix.lockf</code> function. It has been chosen
as primary locking method because it is available everywhere - although
it is not the fastest method.
<p>

The effect of locking is that every read access places read locks
on the relevant parts of the object, and that every write access
acquires the needed write locks. The locking scheme is rather
fine-grained and allows true parallel accesses when a reader and a
writer manipulate the same key of the hash table. Two writers,
however, lock each other out.
<p>

<a name="2_Grouping"></a>
<h2>Grouping</h2>
<p>

Consider this piece of code:
<p>

<pre><code class="code">  let v = Netshm_hashtbl.find tab k in
  let v' = compute_something v in
  Netshm_hashtbl.replace tab k v'
</code></pre>
<p>

This is a so-called read-modify-write cycle. If several processes do this
in parallel, the execution of the cycles can overlap. For example, it
is possible that process P writes the modified value v' while process
Q checks for the value of this key. The outcome of such overlapping
cycles is quite random: In the best case, computations are repeated,
in the worst case, results of computations are lost.
<p>

<a href="Netshm.html"><code class="code">Netshm</code></a> has the function <a href="Netshm.html#VALgroup"><code class="code">Netshm.group</code></a> to avoid such effects:
<p>

<pre><code class="code">  Netshm.group
    (Netshm_hashtbl.shm_table tab)
    (fun () -&gt;
       let v = Netshm_hashtbl.find tab k in
       let v' = compute_something v in
       Netshm_hashtbl.replace tab k v'
    )
    ()
</code></pre>
<p>

Note that you need <a href="Netshm_hashtbl.html#VALshm_table"><code class="code">Netshm_hashtbl.shm_table</code></a> to get the underlying
primitive table in order to use <code class="code">group</code>.
<p>

The effect of <code class="code">group</code> is that conflicting accesses to the same parts
of the memory object are deferred, so that they do not overlap anymore
(technically, the release of the locks is deferred). However, another
phenomenon is now possible: Deadlocks.
<p>

Deadlock situations usually occur between the locking requirements
of a reader and a function that removes a value (<code class="code">remove</code> or <code class="code">replace</code>).
Imagine what happens when processes P and Q execute the same
grouped read-modify-write cycle almost at the same time:
<p>
<ul>
<li>First, both P and Q read-lock the read value</li>
<li>Second, one process is a little bit faster (say P), and wants to
  replace the value, thus needing a write lock. It cannot get
  the write lock now because Q still has a read lock</li>
<li>Third, Q wants to replace the value, needing a write lock.
  It cannot get the write lock now because P still has a read lock</li>
</ul>

If nothing else happened, both processes would wait forever.
<p>

Fortunately, record locking includes deadlock detection. One process
is notified that there is a deadlock. The netshm user gets the
<a href="Netshm.html#EXCEPTIONDeadlock"><code class="code">Netshm.Deadlock</code></a> exception.
<p>

In a simple read-modifiy-write cycle, this exception is quite harmless:
The <code class="code">replace</code> call is interrupted before it got the chance to modify
the table. The suggested strategy to cope 
with that is to sleep for a moment to let the other process do its
job and to restart the cycle from the beginning.
<p>

In a more complicated cycle, it can happen that a value is already
written, and the second trial to write a value triggers the exception.
Well, written is written, and there is no mechanism to "undo"
the chaos. Best strategy: avoid such cycles, or use another way
to store values in a shared storage (e.g. database system).
<p>

<a name="2_Applications"></a>
<h2>Applications</h2>
<p>

I hope it has become clear that netshm is only useful for simple
applications as there is no support for transactions. Another
fundamental limitation is that the file format is non-portable
(netshm files written on platform A may not be readable on
platform B).
<p>

Ideas:
<p>
<ul>
<li>Servers using multi-processing where the processes must share
  some state (e.g. sessions)</li>
<li>Scientific computations implemented on a multi-CPU system with
  multi-processing, where the processes put their results into
  shared memory</li>
<li>Using netshm as fast persistent lookup table</li>
</ul>

<a name="2_Limits"></a>
<h2>Limits</h2>
<p>

The maximum size of a memory object depends on the <code class="code">pagesize</code>
and <code class="code">init</code> parameters of the <code class="code">manage</code> call. Roughly, the
maximum size is
<p>

pagesize * init * 32768
<p>

which is about 8 G for the defaults <code class="code">pagesize</code> = 256 and
<code class="code">init</code> = 1000. Usually, other limits are hit first.
<p>

The hash table and array elements use 32 bit numbers for
their bookkeeping, e.g. strings can have at most a length
of 2 ^ 31 - 1 bytes.
<br>
</body></html>