示例#1
0
文件: ketama.c 项目: lsm/zir
/** \brief Generates the continuum of servers (each server as many points on a circle).
  * \param key Shared memory key for storing the newly created continuum.
  * \param filename Server definition file, which will be parsed to create this continuum.
  * \return 0 on failure, 1 on success. */
static int
ketama_create_continuum( key_t key, char* filename )
{
    int shmid;
    int* data;  /* Pointer to shmem location */
    unsigned int numservers = 0;
    unsigned long memory;
    serverinfo* slist;

    slist = read_server_definitions( filename, &numservers, &memory );
    /* Check numservers first; if it is zero then there is no error message
     * and we need to set one. */
    if ( numservers < 1 )
    {
        sprintf( k_error, "No valid server definitions in file %s", filename );
        return 0;
    }
    else if ( slist == 0 )
    {
        /* read_server_definitions must've set error message. */
        return 0;
    }
#ifdef DEBUG
     syslog( LOG_INFO, "Server definitions read: %u servers, total memory: %lu.\n",
        numservers, memory );
#endif

    /* Continuum will hold one mcs for each point on the circle: */
    mcs continuum[ numservers * 160 ];
    unsigned int i, k, cont = 0;

    for( i = 0; i < numservers; i++ )
    {
        float pct = (float)slist[i].memory / (float)memory;
        unsigned int ks = floorf( pct * 40.0 * (float)numservers );
#ifdef DEBUG
        int hpct = floorf( pct * 100.0 );

        syslog( LOG_INFO, "Server no. %d: %s (mem: %lu = %u%% or %d of %d)\n",
            i, slist[i].addr, slist[i].memory, hpct, ks, numservers * 40 );
#endif

        for( k = 0; k < ks; k++ )
        {
            /* 40 hashes, 4 numbers per hash = 160 points per server */
            char ss[30];
            unsigned char digest[16];

            sprintf( ss, "%s-%d", slist[i].addr, k );
            ketama_md5_digest( ss, digest );

            /* Use successive 4-bytes from hash as numbers 
             * for the points on the circle: */
            int h;
            for( h = 0; h < 4; h++ )
            {
                continuum[cont].point = ( digest[3+h*4] << 24 )
                                      | ( digest[2+h*4] << 16 )
                                      | ( digest[1+h*4] <<  8 )
                                      |   digest[h*4];

                memcpy( continuum[cont].ip, slist[i].addr, 22 );
                cont++;
            }
        }
    }
    free( slist );

    /* Sorts in ascending order of "point" */
    qsort( (void*) &continuum, cont, sizeof( mcs ), (compfn)ketama_compare );

    /* Add data to shmmem */
    shmid = shmget( key, MC_SHMSIZE, 0644 | IPC_CREAT );
    data = shmat( shmid, (void *)0, 0 );
    if ( data == (void *)(-1) )
    {
        strcpy( k_error, "Can't open shmmem for writing." );
        return 0;
    }

    time_t modtime = file_modtime( filename );
    int nump = cont;
    memcpy( data, &nump, sizeof( int ) );
    memcpy( data + 1, &modtime, sizeof( time_t ) );
    memcpy( data + 1 + sizeof( void* ), &continuum, sizeof( mcs ) * nump );

    /* We detatch here because we will re-attach in read-only
     * mode to actually use it. */
    if ( shmdt( data ) == -1 )
        strcpy( k_error, "Error detatching from shared memory!" );

    return 1;
}
示例#2
0
文件: ketama.c 项目: wayfair/ketama
/** \brief Generates the continuum of servers (each server as many points on a circle).
  * \param key Shared memory key for storing the newly created continuum.
  * \param filename Server definition file, which will be parsed to create this continuum.
  * \param contptr The value of this pointer will contain the retrieved continuum resource.
  * \return 0 on failure, 1 on success. */
static int
ketama_create_continuum(key_t key, char* filename, ketama_continuum* contptr)
{
    int shmid, sem_set_id;
    int numservers = 0;
    unsigned long memory;
    serverinfo* slist;
    continuum* data;

    // if filename is not a user-specific key, init a shared memory segment from the pathname, if it's valid
    if (strncmp(filename, "key:", 4) != 0) {
        // get the list of servers from the provided file
        slist = read_server_definitions( filename, &numservers, &memory );

        // Check numservers first; if it is zero then there is no error message and we need to set one.
        if ( numservers < 1 ) {
            snprintf( k_error, sizeof(k_error), "Ketama: No valid server definitions in file %s", filename );
            syslog1( LOG_INFO, k_error );
            return 0;
        } else if ( slist == NULL ) {
            // read_server_definitions must've set error message.
            return 0;
        }

        // log the sucessful file read
        syslog( LOG_INFO, "Ketama: Server definitions read: %u servers, total memory: %lu.\n", numservers, memory );

        time_t fmodtime = file_modtime( filename );

        // attempt to load the continuum and log an error if this fails
        if ( !load_continuum( key, slist, numservers, memory, fmodtime ) ) {
            snprintf( k_error, sizeof(k_error), "Ketama: ketama_create_continuum failed to load the continuum.\n" );
            syslog1( LOG_INFO, k_error );
            return 0;
        }
    }

    // attempt to obtain the shared memory ID assigned to this key, and create a segment if it doesn't exist
    shmid = shmget( key, MC_SHMSIZE, 0644 | IPC_CREAT );
    if ( shmid == -1 ) {
        snprintf( k_error, sizeof(k_error), "Ketama: ketama_create_continuum failed to get valid shared memory segment with errno: %d.\n", errno );
        syslog1( LOG_INFO, k_error );
        return 0;
    }

    // lock the semaphore to prevent other writing to the shared memory segment
    sem_set_id = ketama_sem_init( key );
    ketama_sem_safely_lock( sem_set_id );

    // create an attachment in virtual memory to the shared memory segment, and failout if that an error is returned
    data = (continuum*) shmat( shmid, (void *)0, 0 );
    if ( data == (void *)(-1) ) {
        snprintf( k_error, sizeof(k_error), "Ketama: ketama_create_continuum failed to attach writable shared memory segment with errno: %d.\n", errno );
        syslog1( LOG_INFO, k_error  );
        ketama_sem_unlock( sem_set_id );
        return 0;
    }

    // if filename is not a path, init an empty shared memory segment, otherwise just record the filename
    if (strncmp(filename, "key:", 4) == 0) {
        data->fmodtime = 0;
        data->cont_version = 1;
        data->cont_modtime = time(NULL);
    }
    snprintf(data->cont_filename, sizeof(data->cont_filename), "%s", filename);

    // attempt to detach the shared memory segment and throw an error if one is received
    if (ketama_shmdt(data) == -1) {
        snprintf( k_error, sizeof(k_error), "Ketama: ketama_create_continuum failed to detatch from shared memory with errno: %d.\n", errno );
        syslog1( LOG_INFO, k_error );
    }

    // unlock the semaphore
    ketama_sem_unlock( sem_set_id );

    // rerun ketama_roller with the roller flag on to validate the loaded continuum
    return ketama_roller( contptr, filename, 1);
}