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

« back to all changes in this revision

Viewing changes to src/netplex/netplex_sharedvar.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: netplex_sharedvar.mli 1591 2011-05-05 16:43:45Z gerd $ *)
 
2
 
 
3
(** Netplex-wide variables *)
 
4
 
 
5
(** This plugin allows to have Netplex-global variables that can be read
 
6
    and written by all components. These variables are useful to communicate
 
7
    names and other small pieces of information across the whole Netplex.
 
8
    For instance, one component could allocate a shared memory object, and
 
9
    put its name into a variable to make it known to other components.
 
10
 
 
11
    This implementation works in both multi-processing and
 
12
    multi-threading netplex environments. It is, however, not very
 
13
    fast, because the variables live in the controller, and the
 
14
    access operations are realized by RPC's. It is good
 
15
    enough when these operations are only infrequently called, e.g. in
 
16
    the post-start and pre-finish processor callbacks.
 
17
 
 
18
    Furthermore, note that it is unwise to put large values into
 
19
    variables when using them in multi-processing contexts. The controller
 
20
    process is also the parent process of all [fork]ed children, and
 
21
    when a lot of memory is allocated in the controller, all
 
22
    this memory needs to be copied when the [fork] is done. As workaround,
 
23
    put such values into temporary files, and only pass the names of the
 
24
    files around via variables.
 
25
 
 
26
    Variables come in two flavors:
 
27
     - String variables
 
28
     - Encapsulated variables (see {!Netplex_encap})
 
29
 
 
30
    A string variable cannot be accessed as encapsulated variable, and
 
31
    vice versa.
 
32
 
 
33
    The latter kind is useful to safely store structured ocaml values in
 
34
    Netplex variables.
 
35
 
 
36
    More documentation can also be found here:
 
37
    {!Netplex_advanced.sharedvars}
 
38
 *)
 
39
 
 
40
open Netplex_types
 
41
 
 
42
exception Sharedvar_type_mismatch of string
 
43
  (** The (dynamically typed) variable has the wrong type (string/exn) *)
 
44
 
 
45
exception Sharedvar_no_permission of string
 
46
  (** It is not allowed to set the value *)
 
47
 
 
48
exception Sharedvar_not_found of string
 
49
  (** The variable does not exist. Only used by [Make_var_type] *)
 
50
 
 
51
exception Sharedvar_null
 
52
  (** The initial value of a shared exception variable *)
 
53
 
 
54
 
 
55
val plugin : plugin
 
56
  (** To enable shared variables, call the controller's [add_plugin] method
 
57
      with this object as argument. This can e.g. be done in the
 
58
      [post_add_hook] of the processor.
 
59
   *)
 
60
 
 
61
 
 
62
 
 
63
(** The folloing functions can all be invoked in container
 
64
    contexts. In controller context, access is limited to [get_value].
 
65
 
 
66
    If called from the wrong context the exception
 
67
    {!Netplex_cenv.Not_in_container_thread} is raised. 
 
68
 *)
 
69
 
 
70
val create_var : ?own:bool -> ?ro:bool -> ?enc:bool -> string -> bool
 
71
  (** Create the variable with the passed name with an empty string
 
72
      (or the exception [Sharedvar_null]) as
 
73
      initial value. If the creation is possible (i.e. the variable did
 
74
      not exist already), the function returns [true], otherwise 
 
75
      the already existing variable is left modified, and [false] is
 
76
      passed back. By default, the variable can be modified and deleted
 
77
      by any other container. Two options allow you to change that:
 
78
 
 
79
      - [own]: If true, the created variable is owned by the calling
 
80
        socket service. Only the caller can delete it, and when the 
 
81
        last component of the socket service terminates, the variable is
 
82
        automatically deleted. The deletion happens after the
 
83
        [post_finish_hook] is executed, so the variable is still accessible
 
84
        from this hook.
 
85
      - [ro]: if true, only the owner can set the value
 
86
      - [enc]: if true, the variable stores encapsulated values, otherwise
 
87
        strings
 
88
        (defaults to false)
 
89
 
 
90
      Variable names are global to the whole netplex system. By convention,
 
91
      these names are formed like ["service_name.local_name"], i.e. they
 
92
      are prefixed by the socket service to which they refer.
 
93
   *)
 
94
 
 
95
val delete_var : string -> bool
 
96
  (** [delete_var name]: Deletes the variable [name]. Returns [true] if
 
97
      the deletion could be carried out, and [false] when the variable
 
98
      does not exist, or the container does not have permission to delete
 
99
      the variable.
 
100
   *)
 
101
 
 
102
val set_value : string -> string -> bool
 
103
  (** [set_value name value]: Sets the variable [name] to [value]. This
 
104
      is only possible when the variable exists, and is writable.
 
105
      Returns [true] if the function is successful, and [false] when
 
106
      the variable does not exist.
 
107
 
 
108
      Raises [Sharedvar_no_permission] if the variable cannot be modified.
 
109
 
 
110
      Raises [Sharedvar_type_mismatch] if the variable is not a string
 
111
      variable.
 
112
   *)
 
113
 
 
114
val set_enc_value : string -> encap -> bool
 
115
  (** [set_enc_value name value]: Sets the variable [name] to [value].
 
116
      Return value as for [set_value].
 
117
 
 
118
      Raises [Sharedvar_no_permission] if the variable cannot be modified.
 
119
 
 
120
      Raises [Sharedvar_type_mismatch] if the variable is not encapsulated
 
121
   *)
 
122
 
 
123
val get_value : string -> string option
 
124
  (** [get_value name]: Gets the value of the variable [name]. If the
 
125
      variable does not exist, [None] is returned.
 
126
 
 
127
      Raises [Sharedvar_type_mismatch] if the variable is not a string
 
128
      variable.
 
129
   *)
 
130
 
 
131
val get_enc_value : string -> encap option
 
132
  (** [get_enc_value name]: Gets the value of the variable [name]. If the
 
133
      variable does not exist, [None] is returned.
 
134
 
 
135
      Raises [Sharedvar_type_mismatch] if the variable is not encapsulated
 
136
   *)
 
137
 
 
138
val wait_for_value : string -> string option
 
139
  (** [wait_for_value name]: If the variable exists and [set_value] has
 
140
      already been called at least once, the current value is returned. 
 
141
      If the variable exists, but [set_value] has not yet been called at all,
 
142
      the function waits until [set_value] is called, and returns the value
 
143
      set then. If the variable does not exist, the function immediately
 
144
      returns [None].
 
145
 
 
146
      An ongoing wait is interrupted when the variable is deleted. In this
 
147
      case [None] is returned.
 
148
   *)
 
149
 
 
150
val wait_for_enc_value : string -> encap option
 
151
  (** Same for encapsulated variables *)
 
152
 
 
153
 
 
154
val get_lazily : string -> (unit -> string) -> string option
 
155
  (** [get_lazily name f]: Uses the variable [name] to ensure that [f]
 
156
      is only invoked when [get_lazily] is called for the first time,
 
157
      and that the value stored in the variable is returned the
 
158
      next times. This works from whatever component [get_lazily]
 
159
      is called.
 
160
 
 
161
      If [f()] raises an exception, the exception is suppressed, and
 
162
      [None] is returned as result of [get_lazily]. Exceptions are not
 
163
      stored in the variable, so the next time [get_lazily] is called
 
164
      it is again tried to compute the value of [f()]. If you want to
 
165
      catch the exception this must done in the body of [f].
 
166
 
 
167
      No provisions are taken to delete the variable. If [delete_var]
 
168
      is called by user code (which is allowed at any time), and
 
169
      [get_lazily] is called again, the lazy value will again be computed.
 
170
   *)
 
171
 
 
172
val get_enc_lazily : string -> (unit -> encap) -> encap option
 
173
  (** Same for encapsulated values *)
 
174
 
 
175
val dump : string -> Netlog.level -> unit
 
176
  (** Dumps the access counter of this variable to {!Netlog}. The
 
177
      string argument "*" dumps all variables.
 
178
   *)
 
179
 
 
180
module Make_var_type(T:Netplex_cenv.TYPE) : 
 
181
          Netplex_cenv.VAR_TYPE with type t = T.t
 
182
  (** Creates a module with [get] and [set] functions to access variables
 
183
      of type [T.t]. Call it like
 
184
 
 
185
      {[
 
186
         module Foo_var = 
 
187
           Make_var_type(struct type t = foo end)
 
188
      ]}
 
189
 
 
190
      and use [Foo_var.get] and [Foo_var.set] to access the shared
 
191
      variables of type [foo]. These functions can also raise the exception
 
192
      [Sharedvar_not_found] (unlike the primitive accessors above).
 
193
 
 
194
      The variable must have been created with [enc:true], e.g.
 
195
 
 
196
      {[
 
197
          let ok = create_var ~enc:true "name"
 
198
      ]}
 
199
   *)
 
200
 
 
201
 
 
202
(** Example code:
 
203
 
 
204
    Here, one randomly chosen container computes [precious_value], and
 
205
    makes it available to all others, so the other container can simply
 
206
    grab the value. This is similar to what [get_lazily] does internally:
 
207
 
 
208
    {[
 
209
      let get_precious_value() =
 
210
        let container = Netplex_cenv.self_cont() in
 
211
        let var_name = "my_service.precious" in
 
212
        if Netplex_sharedvar.create_var var_name then (
 
213
          let precious_value = 
 
214
            try ...    (* some costly computation *)
 
215
            with exn ->
 
216
              ignore(Netplex_sharedvar.delete_var var_name);
 
217
              raise exn in
 
218
          let b = Netplex_sharedvar.set_value var_name precious_value in
 
219
          assert b;
 
220
          precious_value
 
221
        )
 
222
        else (
 
223
          match Netplex_sharedvar.wait_for_value var_name with
 
224
           | Some v -> v
 
225
           | None -> failwith "get_precious_value"
 
226
                       (* or do plan B, e.g. compute the value *)
 
227
        )
 
228
    ]}
 
229
 
 
230
    We don't do anything here for deleting the value when it is no longer
 
231
    needed. Finding a criterion for that is very application-specific. 
 
232
    If the variable can be thought as being another service endpoint
 
233
    of a socket service, it is a good idea to acquire the ownership
 
234
    (by passing [~own:true] to [create_var]), so the variable is automatically
 
235
    deleted when the socket service stops.
 
236
 
 
237
    Of course, the plugin must be enabled, e.g. by overriding the 
 
238
    [post_add_hook] processor hook:
 
239
 
 
240
   {[ 
 
241
    method post_add_hook sockserv ctrl =
 
242
      ctrl # add_plugin Netplex_sharedvar.plugin
 
243
   ]}
 
244
 
 
245
 *)
 
246