NAME

    Data::Chronicle - Chronicle storage system

DESCRIPTION

    This package contains three modules (Reader, Writer, and Subscriber)
    which can be used to store and retrieve information on an efficient
    storage with below properties:

 Timeliness

    It is assumed that data to be stored are time-based meaning they change
    over time and the latest version is most important for us.

 Efficient

    The module uses Redis cache to provide efficient data storage and
    retrieval.

 Persistent

    In addition to caching every incoming data, it is also stored in
    PostgreSQL for future retrieval.

 Transparent

    This modules hides all the details about caching, database structure
    and ... from developer. He only needs to call a method to save data and
    another method to retrieve it. All the underlying complexities are
    handled by the module.

    Note that you will need to pass `cache_writer`, `cache_reader` and
    `dbic` to the `Data::Chronicle::Reader/Writer` modules. These three
    arguments, provide access to your Redis and PostgreSQL which will be
    used by Chronicle modules.

    `cache_writer` and `cache_reader` should be to be able to get/set given
    data under given key (both of type string). `dbic` should be capable to
    store and retrieve data with `category`,`name` in addition to the
    timestamp of data insertion. So it should be able to retrieve data for
    a specific timestamp, category and name. Category, name and data are
    all string. This can easily be achieved by defining a table in you
    database containing these columns: `timestamp, category, name, value`.

METHODS

    There are four important methods this module provides:

 "set" in Data::Chronicle::Writer

    Given a category, name and value stores the JSONified value in Redis
    and PostgreSQL database under "category::name" group and also stores
    current system time as the timestamp for the data (Which can be used
    for future retrieval if we want to get data as of a specific time).
    Note that the value MUST be either hash-ref or array-ref.

        $writer->set("category1", "name1", "value1");
        $writer->set("category1", "name2", "value2", Date::Utility->new("2016-08-01 00:06:00"));

 "mset" in Data::Chronicle::Writer

    Given multiple categories, names and values atomically performs the set
    operation on each corresponding category, name, value set.

        $writer->mset([["category1", "name1", $value1], ["category2, "name2", $value2], ...]);

 "get" in Data::Chronicle::Reader

    Given a category and name returns the latest version of the data
    according to current Redis cache

        my $value1 = $reader->get("category1, "name1"); #value1

 "mget" in Data::Chronicle::Reader

    Given multiple categories and name atomically performs the get
    operation on each corresponding category, name set.

        my @values = $reader->mget([["category1", "name1"], ["category2", "name2"], ...])

 "get_for" in Data::Chronicle::Reader

    Given a category, name and timestamp returns version of data under
    "category::name" as of the given date (using a DB lookup).

        my $some_old_data = $reader->get_for("category1", "name2", Date::Utility->new("2016-08-01 00:06:00"));

 "get_for_period" in Data::Chronicle::Reader

    Given a category, name, start_timestamp and end_timestamp returns an
    array-ref containing all data stored between given period for the given
    "category::name" (using a DB lookup).

        my $arrayref = $reader->get_for_period("category1", "name2", Date::Utility->new("2015-08-01 00:06:00"), Date::Utility->new("2015-08-01 00:06:00"));

 "get_history" in Data::Chronicle::Reader

    Given a category, name, and revision returns version of the data the
    specified number of revisions in the past. If revision 0 is chosen, the
    latest version of the data will be returned. If revision 1 is chosen,
    the previous version of the data will be returned.

        my $some_old_data = $reader->get_for("category1", "name2", 2);

 "subscribe" in Data::Chronicle::Subscriber

    Given a category, name, and callback assigns the callback to be called
    when a new value is set for the specified category and name (if the
    writer has publish_on_set enabled).

        $subscriber->subscribe("category1", "name2", sub { print 'Hello World' });

 "unsubscribe" in Data::Chronicle::Subscriber

    Given a category, name, clears the callbacks associated with the
    specified category and name.

        $subscriber->unsubscribe("category1", "name2");

EXAMPLES

        my $d = get_some_log_data();
    
        my $chronicle_w = Data::Chronicle::Writer->new(
            cache_writer => $writer,
            dbic         => $dbic);
    
        my $chronicle_r = Data::Chronicle::Reader->new(
            cache_reader => $reader,
            dbic         => $dbic);
    
    
        #store data into Chronicle - each time we call `set` it will also store
        #a copy of the data for historical data retrieval
        $chronicle_w->set("log_files", "syslog", $d);
    
        #retrieve latest data stored for syslog under log_files category
        my $dt = $chronicle_r->get("log_files", "syslog");
    
        #find historical data for `syslog` at given point in time
        my $some_old_data = $chronicle_r->get_for("log_files", "syslog", $epoch1);