<commit_before>#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <errno.h>
#include <string.h>
#include <unistd.h>

#include "evas_cserve2.h"

#ifdef CSERVE2_BIN_DEFAULT_COLOR
#undef CSERVE2_BIN_DEFAULT_COLOR
#endif
#define CSERVE2_BIN_DEFAULT_COLOR EINA_COLOR_BLUE

#define MAX_SLAVES 3

struct _Slave_Worker {
   EINA_INLIST;
   void *data;
   Slave *slave;
   Eina_Binbuf *ret;
   int ret_size;
   Eina_Bool done;
   Eina_Bool delete_me;
};

typedef struct _Slave_Worker Slave_Worker;

int _evas_cserve2_bin_log_dom = -1;
static unsigned int _client_id = 0;
static Eina_Hash *client_list = NULL;
static Eina_Inlist *slaves_idle = NULL;
static Eina_Inlist *slaves_working = NULL;

void
cserve2_client_error_send(Client *client, unsigned int rid, int error_code)
{
   int size;
   Msg_Error msg;

    // clear the struct with possible paddings, since it is not aligned.
    memset(&msg, 0, sizeof(msg));
    msg.base.rid = rid;
    msg.base.type = CSERVE2_ERROR;
    msg.error = error_code;

    size = sizeof(msg);
    cserve2_client_send(client, &size, sizeof(size));
    cserve2_client_send(client, &msg, sizeof(msg));
}

static void
_cserve2_client_image_setoptsed(Client *client, unsigned int rid)
{
   int size;
   Msg_Setoptsed msg;

   memset(&msg, 0, sizeof(msg));
   msg.base.rid = rid;
   msg.base.type = CSERVE2_SETOPTSED;

   size = sizeof(msg);
   cserve2_client_send(client, &size, sizeof(size));
   cserve2_client_send(client, &msg, size);
}

static void
_slave_dead_cb(Slave *s __UNUSED__, void *data)
{
   Slave_Worker *sw = data;

   if (sw->delete_me)
     {
        DBG("Slave killed by cserve2. Restart routine.");
        free(sw);
        return;
     }

   if (!sw->data)
     {
        WRN("Slave died with no pending job, but not requested.");
        slaves_idle = eina_inlist_remove(slaves_idle, EINA_INLIST_GET(sw));
        free(sw);
        return;
     }

   slaves_working = eina_inlist_remove(slaves_working, EINA_INLIST_GET(sw));
   if (!sw->done)
     cserve2_cache_requests_response(ERROR, (Error_Type[]){ CSERVE2_LOADER_DIED }, sw->data);
   if (sw->ret)
     eina_binbuf_free(sw->ret);
   free(sw);
}

static void
_slave_read_cb(Slave *s __UNUSED__, Slave_Command cmd, void *msg, void *data)
{
   Slave_Worker *sw = data;

   DBG("Received reply command '%d' from slave '%p'", cmd, sw->slave);
   switch (cmd)
     {
      case IMAGE_OPEN:
      case IMAGE_LOAD:
         sw->done = EINA_TRUE;
         break;
      case ERROR:
         break;
      default:
         ERR("Unrecognized command received from slave: %d", cmd);
     }
   cserve2_cache_requests_response(cmd, msg, sw->data);
   free(msg);

   // slave finishes its work, put it back to idle list
   sw->data = NULL;
   slaves_working = eina_inlist_remove(slaves_working, EINA_INLIST_GET(sw));

   if (!sw->delete_me) // if it is being deleted, it shouldn't be in any list
     slaves_idle = eina_inlist_append(slaves_idle, EINA_INLIST_GET(sw));

   cserve2_cache_requests_process();
}

int
cserve2_slave_available_get(void)
{
    return MAX_SLAVES - eina_inlist_count(slaves_working);
}

Eina_Bool
cserve2_slave_cmd_dispatch(void *data, Slave_Command cmd, const void *msg, int size)
{
   Slave_Worker *sw;
   char *exe;

   DBG("Dispatching command to slave. %d idle slaves, %d working slaves.",
       eina_inlist_count(slaves_idle), eina_inlist_count(slaves_working));

   // first check if there's an available slave
   if (slaves_idle)
     {
        sw = EINA_INLIST_CONTAINER_GET(slaves_idle, Slave_Worker);
        slaves_idle = eina_inlist_remove(slaves_idle, slaves_idle);
        slaves_working = eina_inlist_append(slaves_working,
                                            EINA_INLIST_GET(sw));

        sw->data = data;
        DBG("Dispatching command '%d' to slave '%p'", cmd, sw->slave);
        cserve2_slave_send(sw->slave, cmd, msg, size);
        return EINA_TRUE;
     }

   // no available slave, start a new one
   sw = calloc(1, sizeof(Slave_Worker));
   if (!sw) return EINA_FALSE;

   sw->data = data;
   exe = getenv("EVAS_CSERVE2_SLAVE");
   if (!exe) exe = "evas_cserve2_slave";
   sw->slave = cserve2_slave_run(exe, _slave_read_cb, _slave_dead_cb, sw);
   if (!sw->slave)
     {
        ERR("Could not launch slave process");
        cserve2_cache_requests_response(ERROR, (Error_Type[]){ CSERVE2_LOADER_EXEC_ERR }, sw->data);<commit_msg>Mark the slave as not done when it starts a job<commit_after>#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <errno.h>
#include <string.h>
#include <unistd.h>

#include "evas_cserve2.h"

#ifdef CSERVE2_BIN_DEFAULT_COLOR
#undef CSERVE2_BIN_DEFAULT_COLOR
#endif
#define CSERVE2_BIN_DEFAULT_COLOR EINA_COLOR_BLUE

#define MAX_SLAVES 3

struct _Slave_Worker {
   EINA_INLIST;
   void *data;
   Slave *slave;
   Eina_Binbuf *ret;
   int ret_size;
   Eina_Bool done;
   Eina_Bool delete_me;
};

typedef struct _Slave_Worker Slave_Worker;

int _evas_cserve2_bin_log_dom = -1;
static unsigned int _client_id = 0;
static Eina_Hash *client_list = NULL;
static Eina_Inlist *slaves_idle = NULL;
static Eina_Inlist *slaves_working = NULL;

void
cserve2_client_error_send(Client *client, unsigned int rid, int error_code)
{
   int size;
   Msg_Error msg;

    // clear the struct with possible paddings, since it is not aligned.
    memset(&msg, 0, sizeof(msg));
    msg.base.rid = rid;
    msg.base.type = CSERVE2_ERROR;
    msg.error = error_code;

    size = sizeof(msg);
    cserve2_client_send(client, &size, sizeof(size));
    cserve2_client_send(client, &msg, sizeof(msg));
}

static void
_cserve2_client_image_setoptsed(Client *client, unsigned int rid)
{
   int size;
   Msg_Setoptsed msg;

   memset(&msg, 0, sizeof(msg));
   msg.base.rid = rid;
   msg.base.type = CSERVE2_SETOPTSED;

   size = sizeof(msg);
   cserve2_client_send(client, &size, sizeof(size));
   cserve2_client_send(client, &msg, size);
}

static void
_slave_dead_cb(Slave *s __UNUSED__, void *data)
{
   Slave_Worker *sw = data;

   if (sw->delete_me)
     {
        DBG("Slave killed by cserve2. Restart routine.");
        free(sw);
        return;
     }

   if (!sw->data)
     {
        WRN("Slave died with no pending job, but not requested.");
        slaves_idle = eina_inlist_remove(slaves_idle, EINA_INLIST_GET(sw));
        free(sw);
        return;
     }

   slaves_working = eina_inlist_remove(slaves_working, EINA_INLIST_GET(sw));
   if (!sw->done)
     cserve2_cache_requests_response(ERROR, (Error_Type[]){ CSERVE2_LOADER_DIED }, sw->data);
   if (sw->ret)
     eina_binbuf_free(sw->ret);
   free(sw);
}

static void
_slave_read_cb(Slave *s __UNUSED__, Slave_Command cmd, void *msg, void *data)
{
   Slave_Worker *sw = data;

   DBG("Received reply command '%d' from slave '%p'", cmd, sw->slave);
   switch (cmd)
     {
      case IMAGE_OPEN:
      case IMAGE_LOAD:
         sw->done = EINA_TRUE;
         break;
      case ERROR:
         break;
      default:
         ERR("Unrecognized command received from slave: %d", cmd);
     }
   cserve2_cache_requests_response(cmd, msg, sw->data);
   free(msg);

   // slave finishes its work, put it back to idle list
   sw->data = NULL;
   slaves_working = eina_inlist_remove(slaves_working, EINA_INLIST_GET(sw));

   if (!sw->delete_me) // if it is being deleted, it shouldn't be in any list
     slaves_idle = eina_inlist_append(slaves_idle, EINA_INLIST_GET(sw));

   cserve2_cache_requests_process();
}

int
cserve2_slave_available_get(void)
{
    return MAX_SLAVES - eina_inlist_count(slaves_working);
}

Eina_Bool
cserve2_slave_cmd_dispatch(void *data, Slave_Command cmd, const void *msg, int size)
{
   Slave_Worker *sw;
   char *exe;

   DBG("Dispatching command to slave. %d idle slaves, %d working slaves.",
       eina_inlist_count(slaves_idle), eina_inlist_count(slaves_working));

   // first check if there's an available slave
   if (slaves_idle)
     {
        sw = EINA_INLIST_CONTAINER_GET(slaves_idle, Slave_Worker);
        slaves_idle = eina_inlist_remove(slaves_idle, slaves_idle);
        slaves_working = eina_inlist_append(slaves_working,
                                            EINA_INLIST_GET(sw));

        sw->data = data;
        sw->done = EINA_FALSE;
        DBG("Dispatching command '%d' to slave '%p'", cmd, sw->slave);
        cserve2_slave_send(sw->slave, cmd, msg, size);
        return EINA_TRUE;
     }

   // no available slave, start a new one
   sw = calloc(1, sizeof(Slave_Worker));
   if (!sw) return EINA_FALSE;

   sw->data = data;
   exe = getenv("EVAS_CSERVE2_SLAVE");
   if (!exe) exe = "evas_cserve2_slave";
   sw->slave = cserve2_slave_run(exe, _slave_read_cb, _slave_dead_cb, sw);
   if (!sw->slave)
     {
        ERR("Could not launch slave process");
        cserve2_cache_requests_response(ERROR, (Error_Type[]){ CSERVE2_LOADER_EXEC_ERR }, sw->data);
{'fraction_non_alphanumeric': 0.11051975993658703, 'fraction_numerical': 0.007247197372890952, 'mean_word_length': 3.4809741248097414, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 46, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6172352', 'n_tokens_mistral': 3271, 'n_tokens_neox': 3223, 'n_words': 731}