Plasma GitLab Archive
Projects Blog Knowledge

(*
  Copyright 2010 Gerd Stolpmann

  This file is part of Plasma, a distributed filesystem and a
  map/reduce computation framework. Unless you have a written license
  agreement with the copyright holder (Gerd Stolpmann), the following
  terms apply:

  Plasma is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  Plasma is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with Foobar.  If not, see <http://www.gnu.org/licenses/>.

*)
(* $Id: plasma_client.mli 471 2011-10-13 12:14:19Z gerd $ *)

(* Missing:
   - allocate (i.e. acquire blocks without setting eof)
   - get_multi_inodeinfo: pass/return an array of inodes/inodeinfos
     (or error codes). In the db, use a "SELECT id IN set" query.
     Do not update the cache. (This is for "ls" only.)
 *)

(** Client access to the Plasma Filesystem *)

(** This is a client library providing full access to the Plasma filesystem.
    It is probably intuitive to understand this interface, but if any
    question pops up, please consult the page {!Plasmafs_protocol}. It
    explains all background concepts of the PlasmaFS protocol.
 *)

(** Many of the following functions return so-called {i
    engines}. These functions have the suffix [_e]. There is always a
    "normal", i.e.  synchronous variant not returning engines
    computing the result, but directly the result.  The engines make
    it possible to send queries asynchronously.  For more information
    about engines, see the module [Uq_engines] of Ocamlnet. It is
    generally not possible to use the client in a synchronous way when
    an engine is still running.
 *)

(** Some of the following types are defined in {!Plasma_rpcapi_aux},
    especially
    - {!Plasma_rpcapi_aux.inodeinfo}
    - {!Plasma_rpcapi_aux.fsstat}
    - {!Plasma_rpcapi_aux.blockinfo}
 *)
open Plasma_rpcapi_aux

type plasma_cluster
  (** an open Plasma cluster *)

type plasma_trans
  (** plasma transaction *)

type inode = int64
  (** inodes are int64 numbers *)

type errno =
    (* everything but `ok *)
    [ `enotrans | `efailedcommit | `elongtrans | `efailed | `eperm
    | `enoent | `eaccess | `eexist | `efhier | `einval | `efbig
    | `enospc | `erofs | `enametoolong | `econflict | `ecoord
    | `enonode | `etbusy | `eio | `estale | `eloop | `enotdir 
    | `eisdir | `enotempty | `ebadpath
    ]
    (** see {!Pfs_types.errno_code} for documentation *)

type topology = [`Star|`Chain]
    (** see [copy_in] *)

type copy_in_flags = [`No_datasync | `Late_datasync]
    (** see [copy_in] *)

type copy_out_flags = [ `No_truncate ]
    (** see [copy_out] *)

exception Plasma_error of errno
  (** Error reported by the server *)

exception Cluster_down of string
  (** No access to the cluster possible *)


(** {2 Open cluster} *)

val open_cluster : string -> (string * int) list -> Unixqueue.event_system ->
                     plasma_cluster
  (** [open_cluster name namenodes]: Opens the cluster with these namenodes
      (given as [(hostname,port)] pairs). The client automatically
      determines which is the coordinator.
   *)

val open_cluster_cc : Plasma_client_config.client_config ->
                      Unixqueue.event_system ->
                        plasma_cluster
  (** Same, but takes a {!Plasma_client_config.client_config} object which
      can in turn be obtained via {!Plasma_client_config.get_config}.
   *)

val event_system : plasma_cluster -> Unixqueue.event_system
  (** Returns the event system *)

val sync : ('a -> 'b Uq_engines.engine) -> 'a -> 'b
  (** Waits until the event system is done and returns the result of the
      engine
   *)

val dump_buffers : plasma_cluster -> unit
  (** debug report *)

val close_cluster : plasma_cluster -> unit
  (** Closes all file descriptors permanently *)

val abort_cluster : plasma_cluster -> unit
  (** Closes the descriptors to remote services so far possible, but
      does not permanently shut down the client functionality. The
      descriptors are automatically opened again when needed. The
      effect is not only that resources are given back temporarily,
      but also that the pending transactions are aborted.  
   *)

val cluster_name : plasma_cluster -> string
  (** Returns the cluster name *)

val cluster_namenodes : plasma_cluster -> (string * int) list
  (** Returns the namenodes passed to [open_cluster] *)

val configure_buffer : plasma_cluster -> int -> unit
  (** [configure_buffer c n]: configures to use [n] buffers. Each buffer
      is one block. These buffers are only used for buffered I/O, i.e.
      for {!Plasma_client.read} and {!Plasma_client.write}, but not for
      {!Plasma_client.copy_in} and {!Plasma_client.copy_out}.
   *)

val configure_pref_nodes : plasma_cluster -> string list -> unit
  (** Configures that the data nodes with the given identities are
      preferred for the allocation of new blocks. This config is
      active until changed again. Useful for configuring local identities
      (see [local_identities] below), i.e. for enforcing that blocks
      are allocated on the same machine, so far possible.
   *)

val configure_shm_manager : plasma_cluster -> Plasma_shm.shm_manager -> unit
  (** Configures a shared memory manager. This is an optional feature.
      The manager must be configured before the cluster is used.
   *)

val shm_manager : plasma_cluster -> Plasma_shm.shm_manager
  (** Returns the current manager *)

val blocksize_e : plasma_cluster -> int Uq_engines.engine
val blocksize : plasma_cluster -> int
  (** Returns the blocksize *)

val params_e : plasma_cluster -> (string * string) list Uq_engines.engine
val params : plasma_cluster -> (string * string) list
  (** Returns a list of client parameters *)

val fsstat_e : plasma_cluster -> fsstat Uq_engines.engine
val fsstat : plasma_cluster -> fsstat
  (** Return statistics *)

val local_identities_e : plasma_cluster -> string list Uq_engines.engine
val local_identities : plasma_cluster -> string list 
  (** Return the identities of the data nodes running on this machine
      (for [configure_pref_nodes])
   *)


(** {2 Authentication and impersonation} *)

(** There is a distinction between authentication on the RPC level, and
    authentication on the filesystem level. For RPC, the client has only
    the choice between two user IDs, namely "proot" and "pnobody".
    The first has all rights, whereas the latter one can only connect
    (unless it tries to get more rights). Non-privileged clients use
    "pnobody" and provide an additional authentication ticket to obtain
    additional permissions.

    On the filesystem level, the client can take over any user ID independent
    of what ID was used on the RPC level. If "proot" is the RPC user,
    one can just become any filesystem user without credentials. If
    "pnobody" is the RPC user, one needs an authentication ticket to
    become a certain user on the filesystem level.

    There are two ways of getting a ticket:
    - By calling {!Plasma_client.get_auth_ticket} in a session one can obtain
      a ticket, and use it in further sessions to become again the same
      user (via {!Plasma_client.impersonate}).
    - By contacting the authentication daemon, one can get a ticket
      for the Unix-level user ID. (Only on system where this daemon is
      locally runnig.)
 *)

val configure_auth : plasma_cluster -> string -> string -> 
                     (string -> string) -> unit
  (** [configure_auth c nn_user dn_user get_password]: Configures that accesses
      to the namenode are authenticated on the RPC level as [nn_user] and 
      accesses to datanodes
      are authenticated as [dn_user]. The function [get_password] is called
      to obtain the password for a user.

      [nn_user] can be set to "proot" or "pnobody".

      [dn_user] is normally set to "pnobody".

      This type of authentication does not imply any impersonation on the
      filesystem level. One should run {!Plasma_client.impersonate} to
      set something.
   *)

val configure_auth_daemon : plasma_cluster -> unit
  (** Configures that the authentication daemon is contacted to get
      evidence about the current user. If this fails, the namenode
      is contacted anonymously (which normally will also fail).

      This mode also impersonates on the filesystem level.
   *)

val configure_auth_ticket : plasma_cluster -> string -> unit
  (** Configures that this ticket proves the identity of the user.

      This mode also impersonates on the filesystem level.
   *)

val impersonate_e : plasma_cluster -> string -> string -> string list ->
                      string option -> unit Uq_engines.engine
val impersonate : plasma_cluster -> string -> string -> string list ->
                      string option -> unit
  (** [impersonate c user group supp_groups ticket]:
      Become the [user] on the filesystem level. The main group is [group],
      and the supplementary groups are [supp_groups].

      The [ticket] is necessary when the new privileges are not implied
      by the existing privileges (i.e one can only give up rights when
      a ticket is lacking). Examples when a ticket is not required:
      - The user on the RPC level is "proot": existing superuser
        privileges can be given up with [impersonate].
      - The [user] does not change, but only the main [group] is set
        to a different member of the supplementary groups.

      A ticket can be obtained with {!Plasma_client.get_auth_ticket}.

      [impersonate] must not be used inside transactions.
   *)

val get_auth_ticket_e : plasma_cluster -> string -> string Uq_engines.engine
val get_auth_ticket : plasma_cluster -> string -> string
  (** [get_auth_ticket user]: Get an authentication ticket for this [user] *)

val current_user_e : plasma_cluster -> 
                       (string * string * string list) Uq_engines.engine
val current_user : plasma_cluster -> 
                       (string * string * string list)
  (** [let (user,group,supp_groups) = current_user c]: Get the identity
      of the current client principal on the filesystem level.

      Indicates [`efailed] if no impersonation has been done yet.
   *)

val configure_default_user_group : plasma_cluster -> string -> string -> unit
  (** [configure_default_user_group c user group]: Normally, new files are
      created as the user and group corresponding to the current
      impersonation. If privileges permit it, this can changed here so that
      files are created as [user] and [group]. Each string can be empty,
      in which case the value is taken from the impersonation.

      This is especially useful if one authenticates as "proot" and does not
      do any impersonation, i.e. the superuser privileges are still in
      effect. Another use is to create files with a group that is different
      from the main group of the current impersonation.

      This affects not only files, but also new directories and symlinks.
   *)


(** {2 Transactions} *)

(** All functions requiring a [plasma_trans] value as argument must be
    run inside a transaction. This means one has to first call [start]
    to open the transaction, call then the functions covered by the
    transaction, and then either [commit] or [abort].

    It is allowed to open several transactions simultaneously.

    If you use the engine-based interface, it is important to
    ensure that the next function in a transaction can first be
    called when the current function has responded the result.
    This restriction is only valid in the same transaction -
    other transactions are totally independent in this respect.
 *)

val start_e : plasma_cluster -> plasma_trans Uq_engines.engine
val start : plasma_cluster -> plasma_trans
  (** Starts a transaction *)

val commit_e : plasma_trans -> unit Uq_engines.engine
val commit : plasma_trans -> unit 
  (** Commits a transaction, and makes the changes of the transaction
      permanent.
   *)

val abort_e : plasma_trans -> unit Uq_engines.engine
val abort : plasma_trans -> unit 
  (** Aborts a transaction, and abandons the changes of the transaction *)

val cluster : plasma_trans -> plasma_cluster
  (** the cluster to which a transaction belongs *)


(** {2 File creation/access over the inode interface} *)

val create_inode_e : plasma_trans -> inodeinfo -> inode Uq_engines.engine
val create_inode : plasma_trans -> inodeinfo -> inode
  (** Create a new inode. The inode does initially not have a name.

      At the end of the transaction inodes are automatically deleted that
      do not have a name. Use [link_e] to assign names (below).

      See also {!Plasma_client.create_file} below, which immediately
      links the inode to a name. See also {!Plasma_client.regular_ii},
      {!Plasma_client.dir_ii}, and {!Plasma_client.symlink_ii} for
      how to create [inodeinfo] values.
   *)

val delete_inode_e : plasma_trans -> inode -> unit Uq_engines.engine
val delete_inode : plasma_trans -> inode -> unit
  (** Delete the inode *)

val get_inodeinfo_e : plasma_trans -> inode -> inodeinfo Uq_engines.engine
val get_inodeinfo : plasma_trans -> inode -> inodeinfo
  (** Get info about inode. This returns the inodeinfo record from the
      perspective of this transaction.
   *)

val get_cached_inodeinfo_e : plasma_cluster -> inode -> bool ->
                              inodeinfo Uq_engines.engine
val get_cached_inodeinfo : plasma_cluster -> inode -> bool -> inodeinfo
  (** Get info about inode. This function returns the inodeinfo record
      from the cache. The cache can only contain committed versions of the
      inodeinfo record, and it is tried that only recent versions are in
      the cache. If the cache does not contain the data, or if the data is
      out of date, a new transaction is started to get the newest committed
      version.

      The bool argument can be set to [true] to enforce that the
      newest version is retrieved. However, there is no guarantee that
      the returned version is still the newest one when this function
      returns. 

      Note that [get_inodeinfo] also implicitly refreshes the cache when
      the transaction is (still) only used for read accesses.

      The returned inodeinfo does not include modifications caused by
      block writes that were not yet flushed to disk.
 *)

val set_inodeinfo_e : plasma_trans -> inode -> inodeinfo -> 
  unit Uq_engines.engine
val set_inodeinfo : plasma_trans -> inode -> inodeinfo -> unit
  (** set info about inode. Note that setting EOF does neither increase
      nor reduce the number of allocated blocks.
   *)

val truncate_e : plasma_trans -> inode -> int64 -> unit Uq_engines.engine
val truncate : plasma_trans -> inode -> int64 -> unit
  (** Sets EOF value, and all blocks beyond EOF are deallocated. *)


(** {2 Fast sequential data access} *)

(** The function [copy_in] writes a local file to the cluster. [copy_out]
    reads a file from the cluster and copies it into a local file.

    Especially [copy_in] works only in units of whole blocks. The
    function {i never} reads a block from the filesystem, modifies it,
    and writes it back. Instead, it writes the block with the data it
    has, and if there is still space to fill, it pads the block with
    zero bytes. If you need support for updating parts of a block
    only, better use the buffered access below.
 *)

val copy_in_e : ?flags:copy_in_flags list ->
                plasma_cluster -> inode -> int64 -> Unix.file_descr -> int64 -> 
                  topology -> int64 Uq_engines.engine
val copy_in : ?flags:copy_in_flags list ->
              plasma_cluster -> inode -> int64 -> Unix.file_descr -> int64 -> 
                  topology -> int64
  (** [copy_in_e c inode pos fd len]: Copies the data from the file descriptor
      [fd] to the file given by [inode]. The data is taken from the current
      position of the descriptor. Up to [len] bytes are copied. The data 
      is written to position [pos] of the file referenced by the inode. If 
      it is written past the EOF position of the destination file, the EOF
      position is advanced. The function returns the number of copied
      bytes.

      For seekable descriptors, [len] specifies the exact number of bytes
      to copy. If the input file is shorter, null bytes are appended to
      the file until [len] is reached.

      For non-seekable descriptors, an additional buffer needs to be
      allocated. Also, [len] is ignored for non-seekable descriptors -
      data is always copied until EOF is seen.  (However, in the
      future this might be changed. It is better to pass
      [Int64.max_int] as [len] if unlimited copying is required.)

      [topology] says how to transfer data from the client to the data nodes.
      [`Star] means the client organizes the writes to the data nodes as 
      independent streams. [`Chain] means that the data is first written to
      one of the data nodes, and the replicas are transferred from there to
      the next data node.

      [flags]:
      - [`No_datasync]: Data blocks are not synchronized to disk
      - [`Late_datasync]: Only the last block is synchronized to disk.
      This also includes are preceding blocks. If an error occurs, though,
      nothing is guaranteed.

      The default is to write synchronously: At the end of each transaction
      [copy_in] commits, all blocks are guaranteed to be on disk.

      Limitation: [pos] must be a multiple of the blocksize. The file
      is written in units of the blocksize (i.e. blocks are never partially
      updated).

      [copy_in] performs its operations always in separate transactions.
   *)

val copy_in_from_buf_e : ?flags:copy_in_flags list ->
             plasma_cluster -> inode -> int64 -> Netsys_mem.memory -> int -> 
                  topology -> int Uq_engines.engine
val copy_in_from_buf : ?flags:copy_in_flags list ->
              plasma_cluster -> inode -> int64 -> Netsys_mem.memory -> int -> 
                  topology -> int
  (** [copy_in_from_buf c inode pos buf len]: Copies the data from 
      [buf] to the file denoted by [inode]. The data is taken from the
      beginning of [buf], and the length is given by [len]. The data is
      written to position [pos] of [inode].

      [copy_in_from_buf] works much in the same way as [copy_in], only
      that the data is taken from a buffer and not from a file descriptor.
   *)

val copy_out_e : ?flags:copy_out_flags list ->
                 plasma_cluster -> inode -> int64 -> Unix.file_descr -> int64 ->
                   int64 Uq_engines.engine
val copy_out : ?flags:copy_out_flags list ->
               plasma_cluster -> inode -> int64 -> Unix.file_descr -> int64 ->
                   int64
  (** [copy_out_e c inode pos fd len] Copies the data from the file referenced
      by [inode] to file descriptor [fd]. The data is taken from position
      [pos] to [pos+len-1] of the file, and it is written to the current
      position of [fd]. The number of copied bytes is returned.

      Seekable output files may only be extended, but are never truncated.

      For non-seekable descriptors, an additional buffer needs to be allocated.

      If there are holes in the input file, the corresponding byte
      region is filled with zero bytes in the output.
      If it is tried to read past EOF, this is not prevented, but handled
      as if the region past EOF was a file hole.

      Limitation: [pos] must be a multiple of the blocksize.

      [copy_out] performs its operations always in separate transactions.

      Flags:
      - [`No_truncate]: The descriptor [fd] is not truncated to the real
        file size
   *)

val copy_out_to_buf_e : ?flags:copy_out_flags list ->
             plasma_cluster -> inode -> int64 -> Netsys_mem.memory -> int ->
                   int Uq_engines.engine
val copy_out_to_buf : ?flags:copy_out_flags list ->
             plasma_cluster -> inode -> int64 -> Netsys_mem.memory -> int ->
                   int
  (** [copy_out_to_buf_e c inode pos buf len] Copies the data from the
      file denoted by [inode] to the buffer [buf]. The data is taken from
      position
      [pos] to [pos+len-1] of the file, and it is written to the beginning
      of [buf].
   *)


(** {2 Buffered data access} *)

(** For getting well-performing buffered access, you should configure
    the size of the buffer via {!Plasma_client.configure_buffer}.
 *)

type strmem = [`String of string | `Memory of Netsys_mem.memory]
    (** The buffer for [read] and [write] can be given as string or as bigarray
	(memory). The latter is advantageous, because there are some 
	optimizations that are only applicable to bigarrays.
     *)


val read_e : ?lazy_validation:bool ->
             plasma_cluster -> inode -> int64 -> strmem -> int -> int ->
               (int * bool * inodeinfo) Uq_engines.engine
val read : ?lazy_validation:bool ->
           plasma_cluster -> inode -> int64 -> strmem -> int -> int -> 
               int * bool * inodeinfo
  (** [read_e c inode pos s spos len]: Reads data from [inode], and returns
      [(n,eof,ii)] where [n] is the number of read bytes, and [eof] the indicator
      that EOF was reached. This number [n] may be less than [len] only
      if EOF is reached. [ii] is the current inodeinfo.

      Before a [read] is responded from a clean buffer it is checked whether
      the buffer is still up to date.

      By default, [read] updates the metadata from the namenode before starting
      any transaction. By setting [lazy_validation], one can demand a different
      mode, where these updates can be delayed by a short period of time
      (useful when several [read]s are done in sequence).
   *)


type read_request = int64 * strmem * int * int

type read_response = int * bool * inodeinfo

type multi_read_task =
    (read_request * (read_response -> unit))
      option 
        Uq_engines.engine

val multi_read_e : ?lazy_validation:bool ->
                   plasma_cluster -> inode -> multi_read_task Stream.t ->
                     unit Uq_engines.engine
  (** [multi_read_e c inode stream]: This version of [read] allows it
      to read multiple times from the same file. All reads are done in
      the same transaction.

      The function gets the next task from [stream] when the previous
      task is done (if any). A task is always an engine which results
      either in [None] (ending the stream), or in [Some(req,pass_resp)].
      The request [req = (pos, s, spos, len)] says from where to take
      the data and where to store it (like in [read_e]). The 
      response [resp = (n,eof,ii)] is the argument of [pass_resp].
   *)


val write_e : plasma_cluster -> inode -> int64 -> strmem -> int -> int ->
               int Uq_engines.engine
val write : plasma_cluster -> inode -> int64 -> strmem -> int -> int -> 
               int
  (** [write_e c inode pos s spos len]: Writes data to [inode] and returns
      the number of written bytes. This number [n] may be less than [len] for 
      arbitrary reasons (unlike [read] - to be fixed).

      A [write] that is not aligned to a block implies that the old version
      of the block is read first (if not available in a buffer). This is
      a big performance penalty, and best avoided.

      It is not ensured that the write is completed when the return value
      becomes available. The write is actually done in the background,
      and can be explicitly triggered with the [flush_e] operation. Also,
      note that the write happens in a separate transaction. (With
      "background" we do not mean a separate kernel thread, but an
      execution thread modeled with engines.)

      Writing also triggers that the EOF position is at least set to the
      position after the last written position. However, this is first
      done when the blocks are flushed in the background. (Use [get_write_eof]
      to get this value immediately, before flushing.)

      As writing happens in the background, some special attention has to be
      paid for the way errors are reported. At the first error the write thread
      stops, and an error code is set. This code is reported at the next
      [write] or [flush]. After being reported, the code is cleared again.
      Writing is not automatically resumed - only further [write] and
      [flush] invocations will restart the writing thread. Also, the
      data buffers are kept intact after errors - so everything will be
      again tried to be written (which may run into the same error).
      The function [drop_inode] can be invoked to drop all dirty buffers
      of the inode in the near future.
   *)

val get_write_eof : plasma_cluster -> inode -> int64
  (** Returns the designated new EOF value of pending writes.
      Raises [Not_found] if nothing is known.
   *)

val get_write_mtime : plasma_cluster -> inode -> Plasma_rpcapi_aux.time
  (** Returns the designated new mtime value of pending writes.
      Raises [Not_found] if nothing is known.
   *)

val flush_e : plasma_cluster -> inode -> int64 -> int64 -> unit Uq_engines.engine
val flush : plasma_cluster -> inode -> int64 -> int64 -> unit 
  (** [flush_e inode pos len]: Flushes all buffered data of [inode] from
      [pos] to [pos+len-1], or to the end of the file if [len=0]. This
      ensures that data is really written.
   *)

val drop_inode : plasma_cluster -> inode -> unit
  (** Drops all dirty buffers of this inode. This will prevent that they
      are again tried to be written, and it will free up buffer space.
   *)

val flush_all_e : plasma_cluster -> unit Uq_engines.engine
val flush_all: plasma_cluster -> unit 
  (** Flushes all buffers. (No error reporting, though.) *)
  

(** {2 Filename interface} *)

val lookup_e : plasma_trans -> string -> bool -> inode Uq_engines.engine
val lookup : plasma_trans -> string -> bool -> inode
  (** Looks the absolute filename up and returns the inode number 

      The bool says whether to keep the last component of the path
      as symbolic link (lstat semantics).
   *)

val dir_lookup_e : plasma_trans -> inode -> string -> bool -> inode Uq_engines.engine
val dir_lookup : plasma_trans -> inode -> string -> bool -> inode
  (** Looks the filename up relative to a directory (given as inode) 
      and returns the inode number. The filename can also be given as
      relative path.

      If the filename is absolute the inode number is ignored.

      The bool says whether to keep the last component of the path
      as symbolic link (lstat semantics).

      [dir_lookup trans inode "" _] is legal and just returns [inode].
   *)

val rev_lookup_e : plasma_trans -> inode -> string list Uq_engines.engine
val rev_lookup : plasma_trans -> inode -> string list
  (** Returns the filenames linked with this inode number. *)

val rev_lookup_dir_e : plasma_trans -> inode -> string Uq_engines.engine
val rev_lookup_dir : plasma_trans -> inode -> string
  (** Returns the abs filename linked with this inode number which must be
      a directory. The filename is read-locked (i.e. cannot be renamed or
      deleted by a competing transaction).

      It is possible to get an [`econflict] error when the lock requirement
      cannot be satisfied.
   *)

val namelock_e : plasma_trans -> inode -> string -> unit Uq_engines.engine
val namelock : plasma_trans -> inode -> string -> unit
  (** [namelock trans dir name]: Acquires an existence lock on the member
      [name] of directory [dir]. [name] must not contain slashes.

      A namelock prevents that the entry [name] of the directory [dir]
      can be moved or deleted. This protection lasts until the end of
      the transaction. If a concurrent transaction tries to move or 
      delete the file, it will get an [`econflict] error.

      It is not allowed to lock a not yet existing entry.

      It is not prevented that the directory [dir] is moved, and thus it
      is possible that the absolute path of the protected file changes.
   *)

val link_count_e : plasma_trans -> inode -> int Uq_engines.engine
val link_count : plasma_trans -> inode -> int
  (** Returns the number of links (also no locks) *)

val link_e : plasma_trans -> string -> inode -> unit Uq_engines.engine
val link : plasma_trans -> string -> inode -> unit
  (** Links a name with an inode

      For directories there is the restriction that at most one name
      may be linked with the inode.
   *)

val link_at_e : plasma_trans -> inode -> string -> inode -> unit Uq_engines.engine
val link_at : plasma_trans -> inode -> string -> inode -> unit
  (** [link_at trans dir_inode name inode]: Adds the entry [name] into
      the directory [dir_inode] and connects the entry with [inode].
      [name] must not contain slashes.
   *)

val unlink_e : plasma_trans -> string -> unit Uq_engines.engine
val unlink : plasma_trans -> string -> unit
  (** Unlinks the name. If the count of links drops to 0 this also
      removes the inode.

      This also works for directories! (They must be empty, of course.)
   *)

val unlink_at_e : plasma_trans -> inode -> string -> unit Uq_engines.engine
val unlink_at : plasma_trans -> inode -> string -> unit
  (** [unlink_at trans dir_inode name]: Removes the entry [name] from
      the directory [dir_inode]. [name] must not contain slashes.
   *)

val rename_e : plasma_trans -> string -> string -> unit Uq_engines.engine
val rename : plasma_trans -> string -> string -> unit
  (** [rename trans old_path new_path]: Renames/moves the file or directory
      identified by [old_path] to the location identified by [new_path].
      There must not be a file at [new_path] (i.e. you cannot move into
      a directory).
   *)

val rename_at_e : plasma_trans -> inode -> string -> inode -> string ->
                    unit Uq_engines.engine
val rename_at : plasma_trans -> inode -> string -> inode -> string ->
                  unit
  (** [rename_at trans old_dir_inode old_name new_dir_inode new_name]:
      Moves the file [old_name] in [old_dir_inode] to the new location
      which is given by [new_name] in [new_dir_inode].
      Neither [old_name] nor [new_name] must contain slashes.
   *)

val list_inode_e : plasma_trans -> inode ->
                     (string * inode) list Uq_engines.engine
val list_inode : plasma_trans -> inode -> (string * inode) list
  (** Lists the contents of the directory, given by inode 
   *)

val list_e : plasma_trans -> string -> (string * inode) list Uq_engines.engine
val list : plasma_trans -> string -> (string * inode) list
  (** Lists the contents of the directory, given by filename
   *)

val create_file_e : plasma_trans -> string -> inodeinfo -> 
                      inode Uq_engines.engine
val create_file : plasma_trans -> string -> inodeinfo -> inode
  (** Creates a regular file (inode plus name) or a symlink.
      The file type must be
      [`ftype_regular] or [`ftype_symlink].
   *)

val mkdir_e : plasma_trans -> string -> inodeinfo -> inode Uq_engines.engine
val mkdir : plasma_trans -> string -> inodeinfo -> inode
  (** Creates a directory *)

val regular_ii : plasma_cluster -> int -> inodeinfo
  (** [regular_ii c mode]: Creates an inodeinfo record for a new empty
      regular file, where the [mode] field is set to [mode] modulo
      the current mask
   *)

val symlink_ii : plasma_cluster -> string -> inodeinfo
  (** [regular_ii c target]: Creates an inodeinfo record for a symlink
      pointing to [target]
   *)

val dir_ii : plasma_cluster -> int -> inodeinfo
  (** [regular_ii c mode]: Creates an inodeinfo record for a new
      directory, where the [mode] field is set to [mode] modulo
      the current mask
   *)

(** {2 Low-level functions} *)

val get_blocklist_e : plasma_trans -> inode -> int64 -> int64 -> bool ->
                        blockinfo list Uq_engines.engine
val get_blocklist : plasma_trans -> inode -> int64 -> int64 -> bool ->
                        blockinfo list
  (** [get_blocklist_e t inode block n keep_flag] Returns the list of blocks for
      blocks [block] to [blocks+n-1]. This is useful for analyzing where
      the blocks are actually physically stored.

      If [keep_flag] the blocks are protected for the duration of the
      transaction.
   *)

(** {2 Users and groups} *)

val read_admin_table_e : plasma_cluster -> string -> string Uq_engines.engine
val read_admin_table : plasma_cluster -> string -> string
  (** [read_admin_table_e key] Returns the admin table [key] as text.
      Possible keys: "passwd", "group".
   *)

val write_admin_table_e : plasma_cluster -> string -> string -> 
                            unit Uq_engines.engine
val write_admin_table : plasma_cluster -> string -> string -> unit
  (** [write_admin_table_e key file]: Sets the admin table [key] to [file].
      Possible keys: "passwd", "group".
   *)

val read_ug_admin_e : plasma_cluster -> Plasma_ug.ug_admin Uq_engines.engine
val read_ug_admin : plasma_cluster -> Plasma_ug.ug_admin
  (** Read the admin tables for managing users and groups, and make the
      contents available as {!Plasma_ug.ug_admin} object.
   *)

val write_ug_admin_e : plasma_cluster -> Plasma_ug.ug_admin -> 
                         unit Uq_engines.engine
val write_ug_admin : plasma_cluster -> Plasma_ug.ug_admin -> unit
  (** Write the admin tables back (after modification) *)


(** {2 Utilities} *)

val with_trans_e : plasma_cluster -> (plasma_trans -> 'a Uq_engines.engine) ->
                     'a Uq_engines.engine
val with_trans : plasma_cluster -> (plasma_trans -> 'a) -> 'a
  (** [with_trans c f]: Starts a new transaction [t] and runs [f t].
      The transaction is committed if [f] returns normally, and aborted
      if [f] raises an exception.
   *)

val retry_e : plasma_cluster ->
              string -> ('a -> 'b Uq_engines.engine) -> 'a -> 
                'b Uq_engines.engine
val retry : plasma_cluster -> string -> ('a -> 'b) -> 'a -> 'b
  (** [retry c name f arg]: Executes [f arg] and returns the result.
      If an [ECONFLICT] error or timeout occurs the execution is repeated, 
      until a general timeout is reached.

      Errors are logged ({!Netlog}). [name] is used in log output.

      It is common to combine [retry] and [with_trans], e.g.

      {[
         retry c "create_file"
           (fun filename ->
              with_trans c
                (fun trans ->
                   create_file trans filename (regular_ii c 0o666)
                )
           )
      ]}

      implementing the general convention that retry means to retry
      whole transactions.
   *)

This web site is published by Informatikbüro Gerd Stolpmann
Powered by Caml