Go to main content

man pages section 3: Extended Library Functions, Volume 4

Exit Print View

Updated: Wednesday, July 27, 2022
 
 

sstore_data_bulk_update (3SSTORE)

Name

sstore_data_attach, sstore_data_attach_histogram, sstore_data_update, sstore_data_alloc, sstore_data_free, sstore_data_reset, sstore_data_bulk_update - provide statistics to sstored

Synopsis

     cc [ flag... ] file... -lsstore [ library... ]

            #include <libsstore.h>

            typedef struct sstore_data *sstore_data_t;

            sstore_err_t sstore_data_attach(sstore_handle_t hdl,
                const char **ids, uint32_t id_count, uint64_t **addrs);

            sstore_err_t sstore_data_attach_histogram(sstore_handle_t hdl,
                const char *id, sstore_histogram_t hist);

            sstore_err_t sstore_data_update(sstore_handle_t hdl,
                 const char **ids, uint32_t id_count,
                 sstore_value_t *vals);

            sstore_data_t sstore_data_alloc(void);

            void sstore_data_free(sstore_data_t data);
            
            void sstore_data_reset(sstore_data_t data);

            sstore_err_t sstore_data_add(sstore_handle_t hdl,
                sstore_data_t data, uint64_t ts,
                sstore_value_t val);

            sstore_err_t sstore_data_bulk_update(sstore_handle_t hdl,
                const char **ids, uint32_t id_count,
                sstore_data_t *data_arr);

Parameters

hdl

Handle to libsstore

ids

Array of statistics store identifiers

id_count

Total number of statistics store identifiers

id

Statistic store identifier associated with the histogram

hist

sstore_histogram_t to be memory-mapped

vals

Array of values corresponding to the array of statistics store identifiers

addrs

Address to store the starting address of the shared-memory region in the statistics store daemon

data

sstore_data_t containing the data points for a statistic

ts

Timestamp in microseconds since epoch

val

Value for a statistic at a given timestamp

data_arr

Array of sstore_data_t's corresponding to the array of statistics store identifiers

Description

The statistics store provides three methods of updating statistics from a user application: sstore_data_attach(), sstore_data_update(), and sstore_data_bulk_update().

The sstore_data_attach() function is an init routine for counter-type numeric statistics that sets up a shared-memory region between sstored(8) and the client process. Only one call to this function is necessary during the runtime of a client process, after which updates to the stats can be made directly within the shared-memory region.

The sstore_data_attach() function performs the following tasks:

  • Sets up an array of uint64_t shared between the calling process and the sstored daemon.

  • Stores the starting address of this shared array in addrs on success.

  • Enables any resources in the given ssid that are defined statically and are not currently enabled. For more information about statically defined resources, see the sstore(7) man pages.

  • Marks statistics in the given ssids as actively provided.

An ssid at index i in the ids array maps to the i'th element in the addrs array.

For example, to update the value of ids[i] with val:

addrs[i] = val;

The sstore_data_attach_histogram(), like the sstore_data_attach() function, sets up a shared-memory region between sstored(8) and the client process. However, instead of mapping a single counter per statistic, it maps an array of counters corresponding to the buckets in the given histogram. The sstore_histogram_t can then be updated using sstore_histogram_quantize(3SSTORE) and the relevant counter will be updated in the shared memory region.

Note that simply updating the values does not have any impact on sstored(8), and these values are not actually sampled until asked for either through sstore_data_read(3SSTORE) or sstore(1). For more information, see the sstore_data_read(3SSTORE) man page for a description of what trigger data capture in the daemon.

Once capture begins, however, sstore attempts to read from the shared-memory region every second regardless of how quickly the provider updates the value.

Statistics that are updated using the shared-memory method remain mapped by the statistics store daemon until the client either dies or frees the libsstore handle that was used in the sstore_data_attach() call. If the client restarts, then the client must reinitialize the shared memory region with the same statistic ordering as before to be able to provide the statistics again. If the client does not use the same ordering, then the call to the sstore_data_attach() function will fail. If the statistics store daemon restarts but the client does not, the client does not need to reinitialize the shared-memory region.

The sstore_data_update() function allows users to update values of their application statistics for all types of data. This interface is provided for string or other large data types that cannot be written to shared-memory safely without some additional synchronization mechanism. An sstore_data_update() call must be made each time the client wants a value update.

The sstore_data_update() function performs the following tasks:

  • Updates the value of the given ssids with the given values. There is a one to one relationship between the ssids in ids and the values in data.

  • Enables any resources in the given ssid that are defined statically and are not currently enabled. See the sstore(7) man page for information about statically defined resources.

  • Marks statistics in the given ssids as actively provided.

The sstore_data_bulk_update() function allows users to provide multiple data points, that is, a set of (timestamp, value) pairs for a statistic at once. This removes the requirement of providing statistics in real time since the user can provide the timestamp along with the value. However, the data points provided must be in chronological order and hence the client can only provide data points that are more recent than data points that were provided earlier. Any data point that does not meet the above requirement will be ignored.

Any statistic for which data will be provided using this interface also needs to define "min-update-interval", which is the minimum number of seconds between two bulk updates, in its metadata. This field is just a pass-through interface for the consumers like webui(), to set some expectations about the update frequency of a statistic. For more information, see the webui(7) man page.

The sstore_data_bulk_update() function performs the following tasks:

  • Enables any resources in the given ssid that are defined statically and are not currently enabled. For more information about statically defined resources, see the sstore(7)) man pages.

Sampling behavior for the sstore_data_update() and sstore_data_bulk_update() functions are identical to the sstore_data_attach() function. Most importantly, values are only recorded when asked for by the sstore_data_read() function or when persistently enabled. Once it starts recording, a statistic updated through the sstore_data_update() function will be sampled every second using the value received in the most recent update as opposed to a statistic updated through the sstore_data_bulk_update() function which will be sampled as the new data points become available from the statistic provider. For more information on the sampling behaviour, see the sstore_data_read(3SSTORE) man page.

The sstore_data_t is used to provide one or more data points for a statistic using the sstore_data_bulk_update() function.

The sstore_data_alloc() function allocates and returns an sstore_data_t.

The sstore_data_free()function frees the given sstore_data_t and all the data points stored in it.

The sstore_data_reset() function frees all the data points stored in sstore_data_t and resets it back the state when it was alloc'd. This interface allows the client to reuse an sstore_date_t for subsequent calls to sstore_data_bulk_update() function.

The sstore_data_add() function adds a new data point, a timestamp and a value, to sstore_data_t. The data points must be added in chronological order. The sstore_data_add() function makes a copy of the given val, so it can be reused for the next data point.

Authorizations

For a description on the authorizations required to provide and update statistics, see the sstore-security(7) man page.

Return Values

Upon successful completion, sstore_data_update(), and sstore_data_attach() return ESSTORE_OK. Otherwise, they return an error code, which is cached in the given libsstore handle.

Errors

The sstore_data_update() and sstore_data_attach() functions fail if:

ESSTORE_NOMEM

No memory is available

ESSTORE_ARG_INVALID

One of the following reasons:

  • Required arguments are missing

  • Metadata is not available

  • A provider already exists for at least one of the ssids

  • The data type does not match the metadata

  • An ssid is invalid

  • An ssid contains a wildcard or slice

  • An ssid is not a user space statistic or event

ESSTORE_HANDLE_INVALID

The handle is invalid

ESSTORE_RETRY

The statistics store daemon is busy. Retry later

ESSTORE_CONNECTION_FAILED

Failed to connect to the statistics store daemon

ESSTORE_UNAUTHORIZED

The caller is not authorized. For more information, see the sstore-security(7) man page

The sstore_data_add() function fails if:

ESSOTE_ARG_INVALID

One of the following reasons:

  • Required arguments are missing

  • Data point is not in chronological order

  • Data point value does not have same data type as the other data points in sstore_data_t

Examples

Example 1 Using sstore_data_attach()

The following metadata files, installed in /usr/lib/sstore/metadata/json/solaris, are required for this example:

  • class.app.solaris.exapp.json

  • stat.app.solaris.exapp.stat1.json

  • stat.app.solaris.exapp.stat2.json

After installing the files, svc:/system/sstore:default must be restarted.

     class.app.solaris.exapp.json:

     {
        "$schema": "//:class",
        "description": "Example class",
        "id": "app/solaris/exapp",
        "namespaces": [
            {
                "name-type": "string",
                "resource-name": "name"
            }
        ],
        "stability": "stable",
        "static-instances": [
            {
                "name": "exapp/ins",
                "namespace": "name"
            }
        ],
        "stat-names": [
            "//:stat.stat1",
            "//:stat.stat2"
        ]
     }

     stat.app.solaris.exapp.stat1.json:

     {
        "$schema": "//:stat",
        "description": "Example count statistic one",
        "id": "//:class.app/solaris/exapp//:stat.stat1",
        "stability": "stable",
        "type": "counter",
        "units": "calls"
     }

     stat.app.solaris.exapp.stat2.json:

     {
         "$schema": "//:stat",
         "description": "Example count statistic one",
         "id": "//:class.app/solaris/exapp//:stat.stat2",
         "stability": "stable",
         "type": "counter",
         "units": "calls"
     }

     The example program, attach_example.c:

     /*
      * Program to provide statistics values
      */
     #include <libsstore.h>
     #include <stdio.h>
     #include <unistd.h>
     #include <stdlib.h>
     #include <fcntl.h>
     #include <sys/stat.h>
     #include <sys/types.h>

     /* libsstore handle */
     sstore_handle_t hdl;

     /* statistic identifiers */
     char *ids[] = {
             "//:class.app/solaris/exapp//:res.name/exapp/ins//:stat.stat1",
             "//:class.app/solaris/exapp//:res.name/exapp/ins//:stat.stat2"
     };

     /* structure where values are stored */
     struct mystats {
             uint64_t stat1;
             uint64_t stat2;
     };

     int main()
     {
             int iterations = 10;
             struct mystats *stats;

             /* Allocate a libsstore handle */
             if ((hdl = sstore_alloc()) == NULL) {
                     (void) printf("Failed to allocate handle\n");
                     return (-1);
             }

             /*
              * These statistics already have metadata in a common location,
              * so sstore knows how to create them. sstore_data_attach will
              * create a shared-memory region between sstore and this program.
              */
             if (sstore_data_attach(hdl, (const char **)&ids, 2,
                 (uint64_t **)&stats) != ESSTORE_OK) {
                     (void) fprintf(stderr,
                         "Received result message\n\t%s\nfrom sstored "
                         "in sstore_data_attach\n",
                         sstore_err_description(hdl));
                     return (-1);
             }

             /*
              * Update the values in the structure. The new values will be
              * stored when sstore reads them.
              */
             while (iterations-- > 0) {
                     stats->stat1++;
                     stats->stat2 += 3;
                     sleep(1);
             }

             /*
              * Free the libsstore handle.
              * The statistics are marked as not being actively provided.
              */
             sstore_free(hdl);

             return (0);
     }

     Compile this program as follows:

     $ cc -o attach_example attach_example.c -lsstore

     Once the stats store has been restarted, run the following
     command in one terminal to observe the effect of running the
     attach_example program in another terminal:

     $ sstore capture //:class.app/solaris/exapp//:*//:*

     The attach_example program must either be run as root, or a
     user with appropriate stats store privileges. See sstore-security(7)
     for a description of the authorizations required to provide
     and update statistics.
Example 2 Update counter type stats using sstore_data_update()

The following metadata files must be installed in /usr/lib/sstore/metadata/json/solaris, are required for this example:

  • class.example.json

  • stat.example.json

After installing the files, svc:/system/sstore:default must be restarted.

     class.example.json:

     {
        "$schema": "//:class",
        "description": "example class",
        "id": "example",
        "stability": "stable",
        "stat-names": [
            "//:stat.one",
            "//:stat.two"
        ]   
     }

     stat.example.json:

     [
        {   
            "$schema": "//:stat",
            "description": "example stat one",
            "id": "//:class.example//:stat.one",
            "stability": "stable",
            "type": "counter",
            "units": "calls"
        },  
        {   
            "$schema": "//:stat",
            "description": "example stat two",
            "id": "//:class.example//:stat.two",
            "stability": "stable",
            "type": "counter",
            "units": "calls"
        }   
     ]

     /*
      * Example program data_update.c:
      */

     #include <stdio.h>
     #include <stdlib.h>
     #include <unistd.h>
     #include <libsstore.h>

     #define NUM_STATS   2

     const char *ssids[NUM_STATS] = {
         "//:class.example//:stat.one",
         "//:class.example//:stat.two"
     };

     int main()
     {
         sstore_handle_t hdl;
         sstore_value_t vals[NUM_STATS] = {0};
         int i, j;

         if ((hdl = sstore_alloc()) == NULL) {
             fprintf(stderr, "Failed to alloc libsstore handle\n");
             return (-1);
         }

         /* Alloc the sstore_value_t's */
         for (i = 0; i < NUM_STATS; i++) {
             if ((vals[i] = sstore_value_alloc()) == NULL) {
                 fprintf(stderr, "Failed to alloc sstore_value_t\n");
                 goto end;
             }

             vals[i]->sv_type = SSTORE_VALUE_NUMBER;
         }

         /* Update the stats every second */
         for (i = 0;; i++) {
             char *id, *desc;

             for (j = 0; j < NUM_STATS; j++) {
                 vals[j]->sv_value.num += j + 1;
             }

             if (sstore_data_update(hdl, ssids, NUM_STATS,
                 vals) != ESSTORE_OK) {
                     fprintf(stderr, "Failed to update stats. "
                         "Reason: %s\n", sstore_err_description(hdl));
                     break;
             }

             /* Check warnings */
             while (sstore_warning_next(hdl, &id,
                 &desc) != SS_WARN_OK) {
                     fprintf(stderr, "failed to update stat for %s "
                         "because %s\n", id, desc);
             }

             sleep(1);
         }

     end:
         for (i = 0; i < NUM_STATS; i++) {
             sstore_value_free(vals[i]);
         }

         sstore_free(hdl);
         return (0);
     }

     Compile this program as follows:

     $ cc -o data_update -lsstore data_update.c

     Once the sstore has restarted after installing the metadata,
     run 'data_update' as root or as a user with appropriate stats
     store authorizations. See sstore-security(5) for a description
     of the authorizations required to provide and update
     statistics.

     In another terminal, start recording the stats updated via
     data_update as follows:

     $ sstore capture //:class.example//:stat.*

     Sample output:

     $ sstore capture //:class.example//:stat.*
     TIME                VALUE IDENTIFIER
     2016-03-31T13:36:12 6 //:class.example//:stat.one
     2016-03-31T13:36:12 12 //:class.example//:stat.two
     2016-03-31T13:36:13 7 //:class.example//:stat.one
     2016-03-31T13:36:13 14 //:class.example//:stat.two
     2016-03-31T13:36:14 8 //:class.example//:stat.one
     2016-03-31T13:36:14 16 //:class.example//:stat.two
Example 3 Update partitioned stat using sstore_data_update()

The following metadata files, installed in /usr/lib/sstore/metadata/json/solaris, are required for this example:

  • class.example_partition.json

  • stat.example_partition.json

After installing the files, svc:/system/sstore:default must be restarted.

     class.example_partition.json:

     {
        "$schema": "//:class",
        "description": "example class",
        "id": "example/partition",
        "stability": "stable",
        "stat-names": [
            "//:stat.one"
        ]   
     }

     stat.example_partition.json

     {   
        "$schema": "//:stat",
        "description": "example stat one",
        "id": "//:class.example/partition//:stat.one",
        "partitions": [
            "name",
            "place"
        ],
        "stability": "stable",
        "type": "counter",
        "units": "calls"
     }   

     /*
      * Example program data_update_partition.c:
      */

     #include <stdio.h>
     #include <stdlib.h>
     #include <unistd.h>
     #include <libsstore.h>

     #define NUM_STATS   1
     #define NUM_PARTS   2
     #define NUM_KEYS    3

     const char *ssids[NUM_STATS] = {
         "//:class.example/partition//:stat.one"
     };

     const char *example_keys[NUM_PARTS][NUM_KEYS] = {
         { "john", "tom", "bill" },
         { "home", "work", "party" }
     };

     int
     main()
     {
         sstore_handle_t hdl;
         sstore_value_t val = NULL;
         sstore_partition_t part = NULL;
         int i, j;

         if ((hdl = sstore_alloc()) == NULL) {
             fprintf(stderr, "Failed to alloc libsstore handle\n");
             return (-1);
         }

         /* Alloc sstore_partition_t */
         if ((part = sstore_partition_alloc(NUM_PARTS)) == NULL) {
             fprintf(stderr, "Failed to alloc sstore_partition_t\n");
             goto end;
         }
         /* Alloc and init sstore_value_t */
         if ((val = sstore_value_alloc()) == NULL) {
             fprintf(stderr, "Failed to alloc sstore_value_t\n");
             goto end;
         }

         val->sv_type = SSTORE_VALUE_PARTITION;
         val->sv_value.part = part;

         /* Update the stats every second */
         for (i = 0;; i++) {
             char *id, *desc;
             char *keys[NUM_PARTS] = {0};
             uint64_t part_val = i;

             for (j = 0; j < NUM_PARTS; j++) {
                 keys[j] = (char *)example_keys[j][(i + j) % NUM_KEYS];
             }

             if (sstore_partition_inc_value(hdl, part, (const char **)keys,
                 part_val) != ESSTORE_OK) {
                 fprintf(stderr, "Failed to increment partition "
                     "value. Reason: %s\n",
                     sstore_err_description(hdl));
                 break;
             }
                 
             if (sstore_data_update(hdl, ssids, NUM_STATS,
                 &val) != ESSTORE_OK) {
                 fprintf(stderr, "Failed to update stats. "
                     "Reason: %s\n",
                     sstore_err_description(hdl));
                 break;
             }

             /* Check warnings */
             while (sstore_warning_next(hdl, &id, &desc) != SS_WARN_OK) {
                 fprintf(stderr, "failed to update stat for %s "
                     "because %s\n", id, desc);
             }

             sleep(1);
         }

     end:
         sstore_partition_free(part);
         sstore_value_free(val);
         sstore_free(hdl);
         return (0);
     }

     Compile this program as follows:

     $ cc -o data_update_partition -lsstore data_update_partition.c

     Once the sstore has restarted after installing the metadata,
     run 'data_update_partition' as root or as a user with appropriate
     stats store authorizations. See sstore-security(5) for a
     description of the authorizations required to provide and update
     statistics.

     In another terminal, start recording the stats updated via
     data_update as follows:

         sstore capture //:class.example/partition//:stat.one
         sstore capture //:class.example/partition//:stat.one//:part.name
         sstore capture //:class.example/partition//:stat.one//:part.place
         sstore capture "//:class.example/partition//:stat.one//:part.place(party)//:part.name"


     Sample output:

     $ sstore capture //:class.example/partition//:stat.one            
     TIME                VALUE IDENTIFIER
     2016-04-11T17:03:27 703.0 //:class.example/partition//:stat.one
     2016-04-11T17:03:28 741.0 //:class.example/partition//:stat.one
     2016-04-11T17:03:29 780.0 //:class.example/partition//:stat.one

     $ sstore capture //:class.example/partition//:stat.one//:part.name
     TIME                VALUE IDENTIFIER
     2016-04-11T17:03:32  //:class.example/partition//:stat.one//:part.name
                         john: 315.0
                         tom: 287.0
                         bill: 301.0

     $ sstore capture //:class.example/partition//:stat.one//:part.place
     TIME                VALUE IDENTIFIER
     2016-04-11T17:03:35  //:class.example/partition//:stat.one//:part.place
                         work: 360.0
                         party: 330.0
                         home: 345.0
     2016-04-11T17:03:36  //:class.example/partition//:stat.one//:part.place
                         work: 360.0
                         party: 376.0
                         home: 345.0

     $ sstore capture "//:class.example/partition//:stat.one//:part.place(party)//:part.name"
     TIME                VALUE IDENTIFIER
     2016-04-11T17:03:52  //:class.example/partition//:stat.one//:part.place(party)//:part.name
                         tom: 651.0
     2016-04-11T17:03:53  //:class.example/partition//:stat.one//:part.place(party)//:part.name
                         tom: 651.0
Example 4 Update counter type stats using sstore_data_bulk_update()

The following metadata files, installed in /usr/lib/sstore/metadata/json/solaris, are required for this example:

  • class.example_bulk.json

  • stat.example_bulk.json

After installing the files, svc:/system/sstore:default must be restarted.

     class.example_bulk.json:

     {
        "$schema": "//:class",
        "description": "example class",
        "id": "example/bulk",
        "stability": "stable",
        "stat-names": [
            "//:stat.one",
            "//:stat.two"
        ]   
     }

     stat.example_bulk.json:

     [
        {   
            "$schema": "//:stat",
            "description": "example stat one",
            "id": "//:class.example/bulk//:stat.one",
            "min-update-interval": 10,
            "stability": "stable",
            "type": "counter",
            "units": "calls"
        },  
        {   
            "$schema": "//:stat",
            "description": "example stat two",
            "id": "//:class.example/bulk//:stat.two",
            "min-update-interval": 10,
            "stability": "stable",
            "type": "counter",
            "units": "calls"
        }   
     ]

     /*
      * Example program data_bulk_update.c:
      */
     #include <stdio.h>
     #include <stdlib.h>
     #include <unistd.h>
     #include <libsstore.h>

     #define SEC_TO_uSEC(secs)   ((secs)*1000000)

     #define NUM_STATS   2
     #define SLEEP_INTERVAL  10

     const char *ssids[NUM_STATS] = {
         "//:class.example/bulk//:stat.one",
         "//:class.example/bulk//:stat.two"
     };

     /*
      * Gets the current timestamp in microseconds since epoch
      */
     uint64_t
     get_current_ts(void)
     {
         struct timeval tp = {0};

         (void) gettimeofday(&tp, NULL);
         return (SEC_TO_uSEC((uint64_t)tp.tv_sec) + ((uint64_t)tp.tv_usec));
     }

     int
     main()
     {
         sstore_handle_t hdl;
         sstore_value_t vals[NUM_STATS] = {0};
         sstore_data_t data[NUM_STATS] = {0};
         uint64_t now_ts = get_current_ts();
         int i, j;

         if ((hdl = sstore_alloc()) == NULL) {
             fprintf(stderr, "Failed to alloc libsstore handle\n");
             return (-1);
         }

         /* Alloc the sstore_value_t and sstore_data_t's */
         for (i = 0; i < NUM_STATS; i++) {
             if ((vals[i] = sstore_value_alloc()) == NULL) {
                 fprintf(stderr, "Failed to alloc sstore_value_t\n");
                 goto end;
             }

             vals[i]->sv_type = SSTORE_VALUE_NUMBER;
             if ((data[i] = sstore_data_alloc()) == NULL) {
                 fprintf(stderr, "Failed to alloc sstore_data_t\n");
                 goto end;
             }
         }

         /*
          * Bulk update data points for last SLEEP_INTERVAL seconds for
          * each stat
          */
         while (1) {
             char *id, *desc;
             uint64_t ts = now_ts - SEC_TO_uSEC(SLEEP_INTERVAL);

             /* Add data points for each stat */
             for (i = 0; i < SLEEP_INTERVAL; i++, ts += 1000000) {
                 for (j = 0; j < NUM_STATS; j++) {
                     vals[j]->sv_value.num += i + j + 1;
                     if (sstore_data_add(hdl, data[j], ts,
                         vals[j]) != ESSTORE_OK) {
                         fprintf(stderr, "Failed to add "
                             "data point. Reason %s\n",
                             sstore_err_description(hdl));
                         goto end;
                     }
                 }
             }

             /* bulk update */
             if (sstore_data_bulk_update(hdl, ssids, NUM_STATS,
                 data) != ESSTORE_OK) {
                 fprintf(stderr, "Failed to bulk update. "
                     "Reason %s\n",
                     sstore_err_description(hdl));
                 goto end;
             }

             /*
              * Reset sstore_data_t to avoid resending the same data
              * points again
              */
             for (i = 0; i < NUM_STATS; i++) {
                 sstore_data_reset(data[i]);
             }

             /* Check warnings */
             while (sstore_warning_next(hdl, &id, &desc) != SS_WARN_OK) {
                 fprintf(stderr, "failed to bulk update stat for %s "
                     "because %s\n", id, desc);
             }

             sleep(SLEEP_INTERVAL);
             now_ts += SEC_TO_uSEC(SLEEP_INTERVAL);
         }

     end:
         for (i = 0; i < NUM_STATS; i++) {
             sstore_value_free(vals[i]);
             sstore_data_free(data[i]);
         }

         sstore_free(hdl);
         return (0);
     }


     Compile this program as follows:

     $ cc -o data_bulk_update -lsstore data_bulk_update.c

     Once the sstore has restarted after installing the metadata,
     run 'data_bulk_update' as root or as a user with appropriate stats
     store authorizations. See sstore-security(5) for a description
     of the authorizations required to provide and update
     statistics.

     In another terminal, start recording the stats updated via
     data_bulk_update as follows:

     $ sstore capture //:class.example/bulk//:stat.*

     Sample output:

     $ sstore capture //:class.example/bulk//:stat.* 10
     TIME                VALUE IDENTIFIER
     2016-04-11T17:52:06 220 //:class.example/bulk//:stat.one
     2016-04-11T17:52:06 260 //:class.example/bulk//:stat.two
     2016-04-11T17:52:16 275 //:class.example/bulk//:stat.one
     2016-04-11T17:52:16 325 //:class.example/bulk//:stat.two
     2016-04-11T17:52:26 330 //:class.example/bulk//:stat.one
     2016-04-11T17:52:26 390 //:class.example/bulk//:stat.two
Example 5 Update partitioned stat using sstore_data_bulk_update()

The following metadata files, installed in /usr/lib/sstore/metadata/json/solaris, are required for this example:

  • class.example_bulk_partition.json

  • stat.example_bulk_partition.json

After installing the files, svc:/system/sstore:default must be restarted.

     class.example_bulk_partition.json:

     {
        "$schema": "//:class",
        "description": "example class",
        "id": "example/bulk/partition",
        "stability": "stable",
        "stat-names": [
            "//:stat.one"
        ]   
     }

     stat.example_bulk_partition.json

     {   
        "$schema": "//:stat",
        "description": "example stat one",
        "id": "//:class.example/bulk/partition//:stat.one",
        "min-update-interval": 10,
        "partitions": [
            "name",
            "place"
        ],
        "stability": "stable",
        "type": "counter",
        "units": "calls"
     }   

     /*
      * Example program data_bulk_update_partition.c:
      */
     #include <stdio.h>
     #include <stdlib.h>
     #include <unistd.h>
     #include <libsstore.h>

     #define SEC_TO_uSEC(secs)   ((secs)*1000000)

     #define NUM_STATS   1
     #define NUM_PARTS   2
     #define NUM_KEYS    3
     #define SLEEP_INTERVAL  10

     const char *ssids[NUM_STATS] = {
         "//:class.example/bulk/partition//:stat.one"
     };

     const char *example_keys[NUM_PARTS][NUM_KEYS] = {
         { "john", "tom", "bill" },
         { "home", "work", "party" }
     };

     /*
      * Gets the current timestamp in microseconds since epoch
      */
     uint64_t
     get_current_ts(void)
     {
         struct timeval tp = {0};

         (void) gettimeofday(&tp, NULL);
         return (SEC_TO_uSEC((uint64_t)tp.tv_sec) + ((uint64_t)tp.tv_usec));
     }

     int
     main()
     {
         sstore_handle_t hdl;
         sstore_data_t data = NULL;
         sstore_value_t val = NULL;
         sstore_partition_t part = NULL;
         uint64_t now_ts = get_current_ts();
         int i, j;

         if ((hdl = sstore_alloc()) == NULL) {
             fprintf(stderr, "Failed to alloc libsstore handle\n");
             return (-1);
         }

         /* Alloc sstore_partition_t */
         if ((part = sstore_partition_alloc(NUM_PARTS)) == NULL) {
             fprintf(stderr, "Failed to alloc sstore_partition_t\n");
             goto end;
         }

         /* Alloc sstore_data_t */
         if ((data = sstore_data_alloc()) == NULL) {
             fprintf(stderr, "Failed to alloc sstore_data_t\n");
             goto end;
         }

         /* Alloc and init sstore_value_t */
         if ((val = sstore_value_alloc()) == NULL) {
             fprintf(stderr, "Failed to alloc sstore_value_t\n");
             goto end;
         }

         val->sv_type = SSTORE_VALUE_PARTITION;
         val->sv_value.part = part;

         /* bulk update the stat */
         while (1) {
             char *id, *desc;
             char *keys[NUM_PARTS] = {0};
             uint64_t ts = now_ts - SEC_TO_uSEC(SLEEP_INTERVAL);
             
             /* Add data points for the last SLEEP_INTERVAL seconds */
             for (i = 0; i < SLEEP_INTERVAL; i++, ts += 1000000) {
                 uint64_t part_val = i;

                 for (j = 0; j < NUM_PARTS; j++) {
                     keys[j] = (char *)example_keys[j][(i + j) % NUM_KEYS];
                 }

                 if (sstore_partition_inc_value(hdl, part, (const char **)keys,
                     part_val) != ESSTORE_OK) {
                     fprintf(stderr, "Failed to increment partition "
                         "value. Reason: %s\n",
                         sstore_err_description(hdl));
                     break;
                 }
                 
                 if (sstore_data_add(hdl, data, ts, val) != ESSTORE_OK) {
                     fprintf(stderr, "Failed to add data point. "
                         "Reason %s\n",
                         sstore_err_description(hdl));
                     goto end;
                 }
             }

             /* bulk update */
             if (sstore_data_bulk_update(hdl, ssids, NUM_STATS,
                 &data) != ESSTORE_OK) {
                 fprintf(stderr, "Failed to bulk update stat. "
                     "Reason: %s\n",
                     sstore_err_description(hdl));
                 break;
             }

             /*
              * Reset sstore_data_t to avoid resending the same data
              * points again
              */
             sstore_data_reset(data);

             /* Check warnings */
             while (sstore_warning_next(hdl, &id, &desc) != SS_WARN_OK) {
                 fprintf(stderr, "failed to bulk update stat %s "
                     "because %s\n", id, desc);
             }

             sleep(SLEEP_INTERVAL);
             now_ts += SEC_TO_uSEC(SLEEP_INTERVAL);
         }

     end:
         sstore_partition_free(part);
         sstore_value_free(val);
         sstore_data_free(data);
         sstore_free(hdl);
         return (0);
     }


     Compile this program as follows:

     $ cc -o data_bulk_update_partition -lsstore data_bulk_update_partition.c

     Once the sstore has restarted after installing the metadata,
     run 'data_bulk_update_partition' as root or as a user with appropriate
     stats store authorizations. See sstore-security(5) for a
     description of the authorizations required to provide and update
     statistics.

     In another terminal, start recording the stats updated via
     data_bulk_update as follows:

         sstore capture //:class.example/bulk/partition//:stat.one 10
         sstore capture //:class.example/bulk/partition//:stat.one//:part.name 10
         sstore capture //:class.example/bulk/partition//:stat.one//:part.place 10

     Sample output:

     $ sstore capture //:class.example/partition//:stat.one 10           
     TIME                VALUE IDENTIFIER
     2016-04-11T18:10:40 180.0 //:class.example/bulk/partition//:stat.one
     2016-04-11T18:10:50 225.0 //:class.example/bulk/partition//:stat.one

     $ sstore capture //:class.example/partition//:stat.one//:part.name 10
     TIME                VALUE IDENTIFIER
     2016-04-11T18:10:50  //:class.example/bulk/partition//:stat.one//:part.name
                         john: 90.0
                         tom: 60.0
                         bill: 75.0
     2016-04-11T18:10:50  //:class.example/bulk/partition//:stat.one//:part.name
                         john: 90.0
                         tom: 60.0
                         bill: 75.0

     $ sstore capture //:class.example/partition//:stat.one//:part.place 10
     TIME                VALUE IDENTIFIER
     2016-04-11T18:12:35  //:class.example/partition//:stat.one//:part.place
                         work: 252.0
                         party: 168.0
                         home: 210.0
     2016-04-11T18:12:45  //:class.example/partition//:stat.one//:part.place
                         work: 270.0
                         party: 180.0
                         home: 225.0

Attributes

See attributes(7) for descriptions of the following attributes:

ATTRIBUTE TYPE
ATTRIBUTE VALUE
Availability
pkg:/service/system/sstore
Interface Stability
Committed
MT-Level
Safe

See Also

libnvpair(3LIB), libsstore(3LIB), sstore_alloc(3SSTORE), sstore_data_read(3SSTORE), sstore_err_action(3SSTORE), sstore_range_alloc(3SSTORE), attributes(7), privileges(7), sstore(7), sstore-security(7)