#include <stdio.h>
#include <stdlib.h>
#include <csim.h>

#define NUM_CLIENTS 5
#define DB_SIZE 500
#define DATA_SIZE 1024
#define BANDWIDTH 10000
#define CACHE_SIZE 100
#define HOT_DATA_ITEMS 50
#define HOT_DATA_ACCESS_PROB 0.8
#define COLD_DATA_ITEMS (DB_SIZE - HOT_DATA_ITEMS)
#define HOT_DATA_UPDATE_PROB 0.33

int query_count = 0, hit_count = 0, cold_count = 0, update_count = 0;
double query_delay = 0;

int cache[CACHE_SIZE];
int hot_data[HOT_DATA_ITEMS];
int cold_data[COLD_DATA_ITEMS];

double T_QUERY = 5;
double T_UPDATE = 5;

void init_data() {
    int i;
    for (i = 0; i < CACHE_SIZE; i++) {
        cache[i] = -1;
    }
    for (i = 0; i < HOT_DATA_ITEMS; i++) {
        hot_data[i] = rand() % DB_SIZE;
        cold_data[i] = -1;
    }
    for (i = 0; i < COLD_DATA_ITEMS; i++) {
        cold_data[i] = rand() % DB_SIZE;
    }
}

int is_in_cache(int data_id) {
    int i;
    for (i = 0; i < CACHE_SIZE; i++) {
        if (cache[i] == data_id) {
            return 1;
        }
    }
    return 0;
}

void update_cache(int data_id) {
    int i, lru_index = 0, lru_time = simtime() + 1;
    for (i = 0; i < CACHE_SIZE; i++) {
        if (cache[i] == data_id) {
            return;
        }
        if (cache[i] == -1) {
            cache[i] = data_id;
            return;
        }
        if (lastchange(cache[i]) < lru_time) {
            lru_index = i;
            lru_time = lastchange(cache[i]);
        }
    }
    cache[lru_index] = data_id;
}

int find_data(int data_id) {
    int i;
    for (i = 0; i < HOT_DATA_ITEMS; i++) {
        if (hot_data[i] == data_id) {
            return HOT_DATA_ACCESS_PROB >= ((double) rand() / RAND_MAX);
        }
    }
    for (i = 0; i < COLD_DATA_ITEMS; i++) {
        if (cold_data[i] == data_id) {
            return 1;
        }
    }
    cold_count++;
    return 0;
}

double generate_query() {
    int data_id = rand() % DB_SIZE;
    if (is_in_cache(data_id)) {
        query_count++;
        wait(0.001);
        return 0;
    }
    wait(expntl(1.0/T_QUERY));
    if (find_data(data_id)) {
        hit_count++;
        update_cache(data_id);
    }
    query_count++;
    return simtime() - event_time;
}

void generate_update(int data_id) {
    if (HOT_DATA_UPDATE_PROB >= ((double) rand() / RAND_MAX)) {
        hot_data[rand() % HOT_DATA_ITEMS] = data_id;
    } else {
        cold_data[rand() % COLD_DATA_ITEMS] = data_id;
    }
    update_count++;
}

void server() {
    int data_id = rand() % DB_SIZE;
    generate_update(data_id);
    write("Data updated: ");
    writeline(data_id);
    hold(expntl(1.0/T_UPDATE));
}

void client() {
    while (1) {
        generate_query();
    }
}

int main() {
    init_data();
    T_QUERY = 5;
    T_UPDATE = 5;
    set_seed(12345);
    start_simulation(); // Start CSIM simulation
    process(“main”); // Create main process
    int i;
    for (i = 0; i < NUM_CLIENTS; i++) {
        process(client); // Create client processes
    }
    process(server); // Create server process
    hold(10000.0);
    printf(“Total queries: %d, hits: %d, hit rate: %.2f%%\n”, 
           query_count, hit_count, (double) hit_count / query_count * 100);
    printf(“Cold data queries: %d, update count: %d\n”, cold_count, update_count);
    return 0;
}

following code was written for this scenario:
Implement a simple pull-based cache invalidation scheme by using CSIM. In the scheme, a node
generates a query and sends a request message to a server if the queried data item is not found in its local
cache. If the node generates a query that can be answered by its local cache, it sends a check message to
the server for validity. The server replies to the node with a requested data item or a confirm message. A
set of data items is updated in the server. This scheme ensures a strong consistency that guarantees to
access the most updated data items.
2. Refer to the following technical paper and its simulation models (e.g., server, client, caching, data query
and update, etc.):
• G. Cao, "A Scalable Low-Latency Cache Invalidation Strategy for Mobile Environments," ACM
Mobicom, pp. 200-209, 2000
For the sake of simplicity, use the following simulation parameters. Run your simulation several times by
changing the simulation parameters (e.g., T_query and T_update). You can make an assumption and define
your own parameter(s). Then draw result graphs in terms of (i) cache hit ratio and (ii) query delay by
changing mean query generation time and mean update arrival time, similar to Figs. 3 and 4 in the paper.
Note that remove a cold state before collecting any results.
Parameter Values
Number of clients 5
Database (DB) size 500 items
Data item size 1024 bytes
Bandwidth 10000 bits/s
Cache size 100 items
Cache replacement policy LRU
Mean query generate time (T_query) 5, 10, 25, 50, 100 seconds
Hot data items 1 to 50
Cold data items remainder of DB
Hot data access prob. 0.8
Mean update arrival time (T_update) 5, 10, 20, 100, 200 seconds
Hot data update prob. 0.33


can you tell me what event_time is as it is undefined in the program, also add comments in the code explaining major steps