Copyright © 2006-2009 Richard Carlsson
Behaviours: gen_server.
Authors: Richard Carlsson (carlsson.richard@gmail.com).
Erlang file monitoring service
The behaviour of this service is inspired by the open source FAM daemon (http://oss.sgi.com/projects/fam/). It allows file system paths to be monitored, so that a message will be sent to the client process whenever a status change is detected. Currently, the only supported method of detection is by regular polling by the server. While it is not optimal, polling has less overhead than might be expected, and is portable across platforms. The polling interval can be adjusted; by default the server polls all monitored paths every 5 seconds. Recursive (automatic) monitoring is supported. The server keeps track of its client processes, and removes all their monitors if they should die.
{file_monitor, Ref::monitor(), Event}
where Ref
is the monitor reference returned when the monitor was
set up, and Event
is one of the following:
{found, Path::binary(), Type, Info::#file_info{}, Entries::[{added | deleted, Name::binary()}]}
{changed, Path::binary(), Type, Info::#file_info{}, Entries::[{added | deleted, Name::binary()}]}
{error, Path::binary(), Type, PosixError::atom()}
where Path
is the watched path (as a binary), Type
is the type of
monitoring being performed (either file
or directory
), Info
is
a file_info
record as defined in kernel/include/file.hrl
, and
Entries
is a list of tuples {added, binary()}
and {deleted,
binary()}
describing changes to the directory entries if Type
is
directory
, otherwise this is always the empty list. For a found
event, all entries are {added, Name}
.
A found
event is sent when a monitor is initially set up, if the
path can be read. After that, whenever a change in status is
detected, a changed
event is sent. If the file does not exist or
could for some other reason not be accessed, an error
event is sent
(both initially and for subsequent changes). In other words, the
first event for a path is always either found
or error
, and later
events are either changed
or error
.
If the object found at a path changes type in the interval between
two polls, for example if a directory is replaced by a file with the
same name, or vice versa, the file monitor server will detect this
and dispatch an enoent
error event before the new status event. A
client can thus rely on always seeing the old file disappear before
any change that reports a different file type.
There are two ways in which a path can be monitored: as a file
,
meaning that we are interested only in the object found at that path,
or as a directory
, meaning that we expect the path to point to a
directory, and we are also interested in the list of entries of that
directory.
If a path is monitored as a directory, and the object at the path
exists but is not a directory, an enotdir
error event will be
generated. An existing directory can however both be monitored as a
directory and as a file - the difference is that in the latter case,
the reported list of entries will always be empty.
Automatic monitoring (automonitoring for short) can be used to watch
a single file of any type, or a whole directory tree. The monitoring
type (file
or directory
) used for any path is based on the actual
type of object found at the path (directory
if the object is a
readable directory, and file
otherwise). If the object is replaced
by another of different type, the monitoring type will change
automatically.
When a directory becomes automonitored, all of its entries will also be automatically monitored, recursively. As entries are created or deleted in an automonitored directory, they will be dynamically added or removed, respectively, from being monitored. The root path used to create the automonitor will however always remain monitored (even if the object temporarily or permanently disappears) until the server is told to delete the monitor.
The event messages sent to the client are the same as if manual monitoring was done. A newly discovered path will be reported by afound
(or possibly, by an error
event), and subsequent changes on
that path are reported by changed
and error
events. If the
monitoring type is changed, a new found
event is sent, and so on.
filename() = binary() | atom() | [char() | filename()]
This is
an "extended IO-list", that allows atoms as well as binaries to occur
either on their own or embedded in a list or deep list. The intent of
this is to accept any file name that can be used by the standard
library module file
, as well as any normal IO-list, and any list
that is formed by combining such fragments.
monitor() = reference()
A monitor reference.
options() = [term()]
A list of options.
server_ref() = pid() | atom() | {Node::atom(), atom()} | {global, atom()}
A reference to a running server. See //stdlib/gen_server:call/3
for more information.
automonitor(Path::filename()) -> {ok, monitor(), binary()}
Equivalent to automonitor(Path, []).
automonitor(Path::filename(), Opts::options()) -> {ok, monitor(), binary()}
Equivalent to automonitor(file_monitor, Path, Opts).
automonitor(Server::server_ref(), Path::filename(), Opts::options()) -> {ok, monitor(), binary()}
Automonitors the specified path. Returns the monitor reference as well as the monitored path as a binary.
Options: none at present.demonitor(Ref::monitor()) -> ok | {error, not_owner}
Equivalent to demonitor(file_monitor, Ref).
demonitor(Server::server_ref(), Ref::monitor()) -> ok | {error, not_owner}
Deletes the specified monitor. This can only be done by the process that created the monitor.
demonitor_dir(Path::filename(), Ref::monitor()) -> ok | {error, not_owner}
Equivalent to demonitor_dir(file_monitor, Path, Ref).
demonitor_dir(Server::server_ref(), Path::filename(), Ref::monitor()) -> ok | {error, not_owner}
Removes the directory path from the specified monitor. This can only be done by the process that created the monitor.
demonitor_file(Path::filename(), Ref::monitor()) -> ok | {error, not_owner}
Equivalent to demonitor_file(file_monitor, Path, Ref).
demonitor_file(Server::server_ref(), Path::filename(), Ref::monitor()) -> ok | {error, not_owner}
Removes the file path from the specified monitor. This can only be done by the process that created the monitor.
get_interval() -> integer()
Equivalent to get_interval(file_monitor).
get_interval(Server::server_ref()) -> integer()
Returns the current polling interval.
monitor_dir(Path::filename()) -> {ok, monitor(), binary()} | {error, not_owner | automonitor}
Equivalent to monitor_dir(Path, []).
monitor_dir(Path::filename(), Opts::options()) -> {ok, monitor(), binary()} | {error, not_owner | automonitor}
Equivalent to monitor_dir(file_monitor, Path, Opts).
monitor_dir(Server::server_ref(), Path::filename(), Opts::options()) -> {ok, monitor(), binary()} | {error, not_owner | automonitor}
Monitors the specified directory path. Returns the monitor reference as well as the monitored path as a binary.
Options: seemonitor_file/3
.
monitor_file(Path::filename()) -> {ok, monitor(), binary()} | {error, not_owner | automonitor}
Equivalent to monitor_file(Path, []).
monitor_file(Path::filename(), Opts::options()) -> {ok, monitor(), binary()} | {error, not_owner | automonitor}
Equivalent to monitor_file(file_monitor, Path, Opts).
monitor_file(Server::server_ref(), Path::filename(), Opts::options()) -> {ok, monitor(), binary()} | {error, not_owner | automonitor}
Monitors the specified file path. Returns the monitor reference as well as the monitored path as a binary.
Options:{monitor, monitor()}
: specifies a reference for
identifying the monitor to which the path should be added. The
monitor need not already exist, but if it does, only the same
process is allowed to add paths to it, and paths may not be added
manually to an automonitor.normalize_path(Path::filename()) -> binary()
Flattens the given path to a single binary.
set_interval(Time::integer()) -> ok
Equivalent to set_interval(file_monitor, Time).
set_interval(Server::server_ref(), Time::integer()) -> ok
Sets the polling interval. Units are in milliseconds.
start() -> {ok, ServerPid::pid()} | ignore | {error, any()}
Equivalent to start([]).
start(Options::options()) -> {ok, ServerPid::pid()} | ignore | {error, any()}
Equivalent to start({local, file_monitor}, Options).
start(Name::{local, atom()} | {global, atom()} | undefined, Options::options()) -> {ok, ServerPid::pid()} | ignore | {error, any()}
Starts the server and registers it using the specified name.
If the name is undefined
, the server will not be registered. See
//stdlib/gen_server:start_link/4
for details about the return
value.
{interval, Milliseconds::integer()}
start_link() -> {ok, ServerPid::pid()} | ignore | {error, any()}
Equivalent to start_link([]).
start_link(Options::options()) -> {ok, ServerPid::pid()} | ignore | {error, any()}
Equivalent to start_link({local, file_monitor}, Options).
start_link(Name::{local, atom()} | {global, atom()} | undefined, Options::options()) -> {ok, ServerPid::pid()} | ignore | {error, any()}
Starts the server, links it to the current process, and
registers it using the specified name. If the name is undefined
,
the server will not be registered. See //stdlib/gen_server:start_link/4
for details about the return value.
start/2
.
stop() -> ok
Equivalent to stop(file_monitor).
stop(Server::server_ref()) -> ok
Stops the specified server.
Generated by EDoc