~ubuntu-branches/ubuntu/trusty/ocamlnet/trusty

« back to all changes in this revision

Viewing changes to src/netstring/xdr_mstring.mli

  • Committer: Bazaar Package Importer
  • Author(s): Stéphane Glondu
  • Date: 2011-09-02 14:12:33 UTC
  • mfrom: (18.2.3 sid)
  • Revision ID: james.westby@ubuntu.com-20110902141233-zbj0ygxb92u6gy4z
Tags: 3.4-1
* New upstream release
  - add a new NetcgiRequire directive to ease dependency management
    (Closes: #637147)
  - remove patches that were applied upstream:
    + Added-missing-shebang-lines-in-example-shell-scripts
    + Try-also-ocamlc-for-POSIX-threads

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
(* $Id: xdr_mstring.mli 1558 2011-03-04 17:15:46Z gerd $ *)
 
2
 
 
3
(** Managed Strings *)
 
4
 
 
5
(** Managed strings are used in XDR context for constant strings that
 
6
    are stored either as string or as memory (bigarray of char).
 
7
 
 
8
    A managed string [ms] is declared in the XDR file as in
 
9
 
 
10
    {[
 
11
      typedef _managed string ms<>;
 
12
    ]}
 
13
 
 
14
    In the encoded XDR stream there is no difference between strings and
 
15
    managed strings, i.e. the wire representation is identical. Only
 
16
    the Ocaml type differs to which the managed string is mapped. This
 
17
    type is {!Xdr_mstring.mstring} (below).
 
18
 
 
19
    In the RPC context there is often the problem that the I/O backend
 
20
    would profit from a different string representation than the user of
 
21
    the RPC layer. To bridge this gap, managed strings have been invented.
 
22
    Generally, the user can determine how to represent strings (usually
 
23
    either as an Ocaml string, or as memory), and the I/O backend
 
24
    can request to transform to a different representation when this
 
25
    leads to an improvement (i.e. copy operations can be saved).
 
26
 
 
27
    Only large managed strings result in a speedup of the program
 
28
    (at least several K).
 
29
 
 
30
    {2 How to practically use managed strings}
 
31
 
 
32
    There are two cases: The encoding case, and the decoding case.
 
33
    In the encoding case the [mstring] object is created by the user
 
34
    and passed to the RPC library. This happens when a client prepares
 
35
    an argument for calling a remote procedure, or when the server
 
36
    sends a response back to the caller. In the decoding case the client
 
37
    analyzes the response from an RPC call, or the server looks at the
 
38
    arguments of an RPC invocation. The difference here is that in the
 
39
    encoding case user code can directly create [mstring] objects by
 
40
    calling functions of this module, whereas in the decoding case the
 
41
    RPC library creates the [mstring] objects.
 
42
 
 
43
    For simplicity, let us only look at this problem from the perspective
 
44
    of an RPC client.
 
45
 
 
46
    {b Encoding.} Image a client wants to call an RPC, and one of the
 
47
    arguments is a managed string. This means we finally need an [mstring]
 
48
    object that can be put into the argument list of the call.
 
49
 
 
50
    This library supports two string representation specially: The normal
 
51
    Ocaml [string] type, and {!Netsys_mem.memory} which is actually just
 
52
    a bigarray of char's. There are two factories [fac],
 
53
 
 
54
     - {!Xdr_mstring.string_based_mstrings}, and
 
55
     - {!Xdr_mstring.memory_based_mstrings},
 
56
 
 
57
    and both can be used to create the [mstring] to pass to the
 
58
    RPC layer. It should be noted that this layer can process the
 
59
    [memory] representation a bit better. So, if the original [data]
 
60
    value is a string, the factory for [string] should be used, and
 
61
    if it is a char bigarray, the factory for [memory] should be used.
 
62
    Now, the [mstring] object is created by
 
63
 
 
64
     - [let mstring = fac # create_from_string data pos len copy_flag], or by
 
65
     - [let mstring = fac # create_from_memory data pos len copy_flag].
 
66
 
 
67
    Of course, if [fac] is the factory for strings, the [create_from_string]
 
68
    method works better, and if [fac] is for [memory], the [create_from_memory]
 
69
    method works better. [pos] and [len] can select a substring of [data].
 
70
    If [copy_flag] is [false], the [mstring] object does not copy the data
 
71
    if possible, but just keeps a reference to [data] until it is accessed;
 
72
    otherwise if [copy_flag] is [true], a copy is made immediately.
 
73
    Of couse, delaying the copy is better, but this requires that [data]
 
74
    is not modified until the RPC call is completed.
 
75
 
 
76
    {b Decoding.} Now, the call is done, and the client looks at the
 
77
    result. There is also an [mstring] object in the result. As noted
 
78
    above, this [mstring] object was already created by the RPC library
 
79
    (and currently this library prefers string-based objects if not
 
80
    told otherwise). The user code can now access this [mstring]
 
81
    object with the access methods of the [mstring] class (see below).
 
82
    As these methods are quite limited, it makes normally only sense
 
83
    to output the [mstring] contents to a file descriptor.
 
84
 
 
85
    The user can request a different factory for managed strings. The 
 
86
    function {!Rpc_client.set_mstring_factories} can be used for this
 
87
    purpose. (Similar ways exist for managed clients, and for RPC servers.)
 
88
 
 
89
    {b Potential.} Before introducing managed strings, a clean analysis
 
90
    was done how many copy operations can be avoided by using this
 
91
    technique. Example: The first N bytes of a file are taken as 
 
92
    argument of an RPC call. Instead of reading these bytes into a
 
93
    normal Ocaml string, an optimal implementation uses now a [memory]
 
94
    buffer for this purpose. This gives:
 
95
 
 
96
    - Old implementation with strings and ocamlnet-2:
 
97
      Data is copied {b six} times from reading it from the file until
 
98
      writing it to the socket.
 
99
    - New implementation with memory-based mstrings:
 
100
      Data is copied only {b twice}! The first copy reads it from the
 
101
      file into the input buffer (a [memory] value), and the second copy
 
102
      writes the data into the socket.
 
103
 
 
104
    Part of the optimization is that [Unix.read] and [Unix.write]
 
105
    do a completely avoidable copy of the data which is prevented by
 
106
    switching to {!Netsys_mem.mem_read} and {!Netsys_mem.mem_write},
 
107
    respectively. The latter two functions exploit an optimization
 
108
    that is only possible when the data is [memory]-typed.
 
109
 
 
110
    The possible optimizations for the decoding side of the problem
 
111
    are slightly less impressive, but still worth doing it.
 
112
 *)
 
113
 
 
114
(** {2 Interface} *)
 
115
 
 
116
open Netsys_mem
 
117
 
 
118
(** The object holding the string value *)
 
119
class type mstring =
 
120
object
 
121
  method length : int
 
122
    (** The length of the managed string *)
 
123
 
 
124
  method blit_to_string :  int -> string -> int -> int -> unit
 
125
    (** [blit_to_string mpos s spos len]: Copies the substring of the
 
126
        managed string from [mpos] to [mpos+len-1] to the substring of
 
127
        [s] from [spos] to [spos+len-1]
 
128
     *)
 
129
 
 
130
  method blit_to_memory : int -> memory -> int -> int -> unit
 
131
    (** [blit_to_string mpos mem mempos len]: Copies the substring of the
 
132
        managed string from [mpos] to [mpos+len-1] to the substring of
 
133
        [mem] from [mempos] to [mempos+len-1]
 
134
     *)
 
135
 
 
136
  method as_string : string * int
 
137
    (** Returns the contents as string. It is undefined whether the returned
 
138
        string is a copy or the underlying buffer. The int is the position
 
139
        where the contents start
 
140
     *)
 
141
 
 
142
  method as_memory : memory * int
 
143
    (** Returns the contents as memory. It is undefined whether the returned
 
144
        memory is a copy or the underlying buffer. The int is the position
 
145
        where the contents start
 
146
     *)
 
147
 
 
148
  method preferred : [ `Memory | `String ]
 
149
    (** Whether [as_memory] or [as_string] is cheaper *)
 
150
 
 
151
end
 
152
 
 
153
 
 
154
(** The object creating new [mstring] objects *)
 
155
class type mstring_factory =
 
156
object
 
157
  method create_from_string : string -> int -> int -> bool -> mstring
 
158
    (** [create_from_string s pos len must_copy]: Creates the [mstring] from the
 
159
        sub string of s starting at [pos] with length [len]
 
160
 
 
161
        If [must_copy] the mstring object must create a copy. Otherwise
 
162
        it can just keep the string passed in.
 
163
     *)
 
164
 
 
165
  method create_from_memory : memory -> int -> int -> bool -> mstring
 
166
    (** [create_from_memory m pos len must_copy]: Creates the [mstring] from the
 
167
        sub string of m starting at [pos] with length [len]
 
168
 
 
169
        If [must_copy] the mstring object must create a copy. Otherwise
 
170
        it can just keep the memory passed in.
 
171
     *)
 
172
 
 
173
end
 
174
 
 
175
val string_based_mstrings : mstring_factory
 
176
  (** Uses strings to represent mstrings *)
 
177
 
 
178
val string_to_mstring : ?pos:int -> ?len:int -> string -> mstring
 
179
  (** Represent a string as mstring (no copy) *)
 
180
 
 
181
val memory_based_mstrings : mstring_factory
 
182
  (** Uses memory to represent mstrings. The memory bigarrays are allocated
 
183
      with [Bigarray.Array1.create]
 
184
   *)
 
185
 
 
186
val memory_to_mstring : ?pos:int -> ?len:int -> memory -> mstring
 
187
  (** Represent memory as mstring (no copy) *)
 
188
 
 
189
val paligned_memory_based_mstrings : mstring_factory
 
190
  (** Uses memory to represent mstrings. The memory bigarrays are allocated
 
191
      with {!Netsys_mem.alloc_memory_pages} if available, and 
 
192
      [Bigarray.Array1.create] if not.
 
193
   *)
 
194
 
 
195
val memory_pool_based_mstrings : Netsys_mem.memory_pool -> mstring_factory
 
196
  (** Uses memory to represent mstrings. The memory bigarrays are obtained
 
197
      from the pool. The length of these mstrings is limited by the 
 
198
      blocksize of the pool.
 
199
   *)
 
200
 
 
201
val length_mstrings : mstring list -> int
 
202
  (** returns the sum of the lengths of the mstrings *)
 
203
 
 
204
val concat_mstrings : mstring list -> string
 
205
  (** concatenates the mstrings and return them as single string. The returned
 
206
      string may be shared with one of the mstrings passed in.
 
207
   *)
 
208
 
 
209
val prefix_mstrings : mstring list -> int -> string
 
210
  (** [prefix_mstrings l n]: returns the first [n] chars of the 
 
211
      concatenated mstrings [l] as single string
 
212
   *)
 
213
 
 
214
val blit_mstrings_to_memory : mstring list -> memory -> unit
 
215
  (** blits the mstrings one after the other to the memory, so that
 
216
      they appear there concatenated
 
217
   *)
 
218
 
 
219
val shared_sub_mstring : mstring -> int -> int -> mstring
 
220
  (** [shared_sub_mstring ms pos len]: returns an mstring that includes
 
221
      a substring of [ms], starting at [pos], and with [len] bytes. 
 
222
      The returned mstring shares the buffer with the original mstring [ms]
 
223
   *)
 
224
 
 
225
val shared_sub_mstrings : mstring list -> int -> int -> mstring list
 
226
  (** Same for a list of mstrings *)
 
227
 
 
228
val copy_mstring : mstring -> mstring
 
229
  (** Create a copy *)
 
230
 
 
231
val copy_mstrings : mstring list -> mstring list
 
232
  (** Create a copy *)
 
233
 
 
234
 
 
235
type named_mstring_factories =
 
236
    (string, mstring_factory) Hashtbl.t