#ifndef THREAD_LOCAL_COUNTER_H
#define THREAD_LOCAL_COUNTER_H

// Overview: A partitioned_counter provides a counter that can be incremented and the running sum can be read at any time.
//  We assume that increments are frequent, whereas reading is infrequent.
// Implementation hint: Use thread-local storage so each thread increments its own data.  The increment does not require a lock or atomic operation.
//  Reading the data can be performed by iterating over the thread-local versions, summing them up.
//  The data structure also includes a sum for all the threads that have died.
//  Use a pthread_key to create the thread-local versions.  When a thread finishes, the system calls pthread_key destructor which can add that thread's copy
//  into the sum_of_dead counter.
// Rationale: For statistics such as are found in engine status, we need a counter that requires no cache misses to increment.  We've seen significant
//  performance speedups by removing certain counters.  Rather than removing those statistics, we would like to just make the counter fast.
//  We generally increment the counters frequently, and want to fetch the values infrequently.
//  The counters are monotonic.
//  The counters can be split into many counters, which can be summed up at the end.
//  We don't care if we get slightly out-of-date counter sums when we read the counter.  We don't care if there is a race on reading the a counter
//   variable and incrementing.
//  See tests/test_partitioned_counter.c for some performance measurements.
// Operations:
//   create_partitioned_counter    Create a counter initialized to zero.
//   destroy_partitioned_counter   Destroy it.
//   increment_partitioned_counter Increment it.  This is the frequent operation.
//   read_partitioned_counter      Get the current value.  This is infrequent.

typedef struct partitioned_counter *PARTITIONED_COUNTER;
PARTITIONED_COUNTER create_partitioned_counter(void);
// Effect: Create a counter, initialized to zero.

void destroy_partitioned_counter (PARTITIONED_COUNTER);
// Effect: Destroy the counter.  No operations on that counter are permitted after this.

void increment_partitioned_counter (PARTITIONED_COUNTER, unsigned long amount);
// Effect: Increment the counter by amount.
// Requires: No overflows.  This is a 64-bit unsigned counter.

unsigned long read_partitioned_counter (PARTITIONED_COUNTER);
// Effect: Return the current value of the counter.

#endif