Пример #1
0
static void buildRetrievalResponse(struct ramcloudData *d, int cas)
{
    int i = 0;
    char buf[64];
    ASSERT(!d->retrieval_response);
    // Estimate value avoid realloc
    d->retrieval_response = wstrNewLen(NULL, d->retrieval_len+narray(d->retrievals_vals)*64);
    for (; i < narray(d->retrievals_vals); ++i) {
        struct slice *val = arrayIndex(d->retrievals_vals, i);
        struct slice *key = arrayIndex(d->retrievals_keys, i);
        uint16_t *flag = arrayIndex(d->retrievals_flags, i);
        uint64_t *v = arrayIndex(d->retrievals_versions, i);
        d->retrieval_response = wstrCatLen(d->retrieval_response, VALUE, 5);
        d->retrieval_response = wstrCatLen(d->retrieval_response, " ", 1);
        d->retrieval_response = wstrCatLen(d->retrieval_response, (char*)key->data, key->len);
        d->retrieval_response = wstrCatLen(d->retrieval_response, " ", 1);
        int l = sprintf(buf, "%d", *flag);
        d->retrieval_response = wstrCatLen(d->retrieval_response, buf, l);
        d->retrieval_response = wstrCatLen(d->retrieval_response, " ", 1);
        l = sprintf(buf, "%ld", val->len);
        d->retrieval_response = wstrCatLen(d->retrieval_response, buf, l);
        if (cas) {
            d->retrieval_response = wstrCatLen(d->retrieval_response, " ", 1);
            l = sprintf(buf, "%llu", *v);
            d->retrieval_response = wstrCatLen(d->retrieval_response, buf, l);
        }
        d->retrieval_response = wstrCatLen(d->retrieval_response, CRLF, 2);
        d->retrieval_response = wstrCatLen(d->retrieval_response, (char*)val->data, val->len);
        d->retrieval_response = wstrCatLen(d->retrieval_response, CRLF, 2);
    }

    d->retrieval_response = wstrCatLen(d->retrieval_response, END, 3);
    d->retrieval_response = wstrCatLen(d->retrieval_response, CRLF, 2);
}
Пример #2
0
// hashAdd is used when a new redis server add to rebalance tokens
int hashAdd(struct redisServer *server, wstr ip, int port, int id)
{
    size_t ninstance, ntoken_per_instance, extra_ntoken, target_idx, ntoken;
    struct token *token, *tokens;
    struct redisInstance *instance, *target_instance;
    struct redisInstance add_instance;
    size_t *sub_ntoken;
    int i;

    if (initInstance(&add_instance, id, ip, port, DIRTY) == WHEAT_WRONG)
        return WHEAT_WRONG;
    arrayPush(server->instances, &add_instance);

    // `sub_ntoken`'s element is the amount of tokens every instance should
    // take out
    ninstance = narray(server->instances);
    sub_ntoken = wmalloc(sizeof(int)*ninstance);
    ntoken_per_instance = WHEAT_KEYSPACE / ninstance;
    extra_ntoken = WHEAT_KEYSPACE % ninstance;
    for (i = 0; i < ninstance; i++) {
        instance = arrayIndex(server->instances,i);
        sub_ntoken[i] = instance->ntoken - ntoken_per_instance;
    }
    if (!extra_ntoken) {
        for (i = 0; i < extra_ntoken; i++) {
            sub_ntoken[i]--;
        }
    }

    target_idx = ninstance-1;
    extra_ntoken = sub_ntoken[target_idx];
    target_instance = arrayIndex(server->instances, target_idx);
    token = tokens = &server->tokens[0];
    while (extra_ntoken) {
        size_t skip = random() % ntoken_per_instance + 1;
        while (skip--) {
            token = &tokens[token->next_instance];
        }
        if (token->instance_id != target_idx &&
                sub_ntoken[token->instance_id]) {
            wheatLog(WHEAT_DEBUG, "token: %d", token->pos);
            instance = arrayIndex(server->instances, token->instance_id);
            token->instance_id = target_idx;
            instance->ntoken--;
            target_instance->ntoken++;
        }
    }

    ntoken = 0;
    for (i = 0; i < ninstance; i++) {
        instance = arrayIndex(server->instances,i);
        ntoken += instance->ntoken;
    }
    ASSERT(ntoken == WHEAT_KEYSPACE);

    wfree(sub_ntoken);
    return WHEAT_OK;
}
Пример #3
0
int spotMemcache(struct conn *c)
{
    int ret;
    struct app **app_p, *app;

    app_p = arrayIndex(WorkerProcess->apps, 0);
    app = *app_p;
    if (!app->is_init) {
        ret = initApp(app);
        if (ret == WHEAT_WRONG)
            return WHEAT_WRONG;
    }
    c->app = app;
    ret = initAppData(c);
    if (ret == WHEAT_WRONG) {
        wheatLog(WHEAT_WARNING, "init app data failed");
        return WHEAT_WRONG;
    }
    ret = app->appCall(c, NULL);
    if (ret == WHEAT_WRONG) {
        wheatLog(WHEAT_WARNING, "app failed, exited");
        app->deallocApp();
        app->is_init = 0;
    }
    finishConn(c);
    return ret;
}
Пример #4
0
static void ramcloudSet(struct ramcloudData *d, wstr key, struct array *vals, uint32_t vlen, uint16_t flag, struct RejectRules *rule)
{
    wheatLog(WHEAT_DEBUG, "%s set key %s", __func__, key);
    uint64_t version;
    int i = 0;
    struct slice *slice;
    wstr val = wstrNewLen(NULL, vlen+sizeof(flag));
    while (i < narray(vals)) {
        slice = arrayIndex(vals, i);
        val = wstrCatLen(val, (char*)slice->data, slice->len);
        ++i;
    }
    val = wstrCatLen(val, (char*)&flag, FLAG_SIZE);

    Status s = rc_write(global.client, d->table_id, key, wstrlen(key), val, wstrlen(val),
                        rule, &version);
    wstrFree(val);
    if (s != STATUS_OK) {
        // cas command
        if (rule->versionNeGiven) {
            if (s == STATUS_WRONG_VERSION)
                sliceTo(&d->storage_response, (uint8_t*)EXISTS, sizeof(EXISTS)-1);
            else if (s == STATUS_OBJECT_DOESNT_EXIST)
                sliceTo(&d->storage_response, (uint8_t*)NOT_FOUND, sizeof(NOT_FOUND)-1);
        } else if ((rule->doesntExist && s == STATUS_OBJECT_DOESNT_EXIST) ||
                   (rule->exists && s == STATUS_OBJECT_EXISTS)) {
            sliceTo(&d->storage_response, (uint8_t*)NOT_STORED, sizeof(NOT_STORED)-1);
        } else {
            wheatLog(WHEAT_WARNING, "%s failed to set %s: %s", __func__, key, statusToString(s));
            sliceTo(&d->storage_response, (uint8_t*)SERVER_ERROR, sizeof(SERVER_ERROR)-1);
        }
    } else {
        sliceTo(&d->storage_response, (uint8_t*)STORED, sizeof(STORED)-1);
    }
}
Пример #5
0
// Only called when config-server is not specifyed. Means that WheatRedis is
// firstly running on your system.
int hashInit(struct redisServer *server)
{
    ASSERT(narray(server->instances) >= server->nbackup);
    struct redisInstance *instance;
    size_t ntoken, ninstance, swap;
    int i, prev_idx;
    struct token *tokens = server->tokens, *last_token = NULL;

    ntoken = WHEAT_KEYSPACE;
    tokens = wmalloc(sizeof(struct token)*ntoken);
    if (!tokens)
        return WHEAT_WRONG;
    server->tokens = tokens;

    ninstance = narray(server->instances);
    for (i = 0; i < ntoken; ++i) {
        instance = arrayIndex(server->instances, i%ninstance);
        tokens[i].next_instance = UINT32_MAX; // An impossible value
        tokens[i].pos = i;
        tokens[i].instance_id = i%ninstance;
        instance->ntoken++;
    }

    // shuffle
    for (i = 0; i < ntoken; i++)
    {
        size_t j = i + rand() / (RAND_MAX / (ntoken - i) + 1);
        swap = tokens[j].instance_id;
        tokens[j].instance_id = tokens[i].instance_id;
        tokens[i].instance_id = swap;
    }

    // Populate each token.next_instance to quicker search node process
    prev_idx = 0;
    i = 1;
    last_token = &tokens[ntoken-1];
    while (last_token->next_instance == UINT32_MAX) {
        if (tokens[i%ntoken].instance_id != tokens[prev_idx].instance_id) {
            for (; prev_idx < i && prev_idx < ntoken; ++prev_idx)
                tokens[prev_idx].next_instance = i%ntoken;
        }
        ++i;
    }
    server->ntoken = ntoken;
    return WHEAT_OK;
}
Пример #6
0
void initWorkerProcess(struct workerProcess *worker, char *worker_name)
{
    struct configuration *conf;
    int i;
    struct app *app;
    struct moduleAttr *module;

    if (Server.stat_fd != 0)
        close(Server.stat_fd);
    setProctitle(worker_name);
    worker->pid = getpid();
    worker->ppid = getppid();
    worker->alive = 1;
    worker->start_time = Server.cron_time;
    worker->worker = spotWorker(worker_name);
    worker->master_stat_fd = 0;
    ASSERT(worker->worker);
    worker->stats = NULL;
    initWorkerSignals();
    worker->center = eventcenterInit(WHEAT_CLIENT_MAX);
    if (!worker->center) {
        wheatLog(WHEAT_WARNING, "eventcenter_init failed");
        halt(1);
    }
    if (createEvent(worker->center, Server.ipfd, EVENT_READABLE, acceptClient,  NULL) == WHEAT_WRONG)
    {
        wheatLog(WHEAT_WARNING, "createEvent failed");
        halt(1);
    }

    // It may nonblock after fork???
    if (wheatNonBlock(Server.neterr, Server.ipfd) == NET_WRONG) {
        wheatLog(WHEAT_WARNING, "Set nonblock %d failed: %s", Server.ipfd, Server.neterr);
        halt(1);
    }

    module = NULL;
    conf = getConfiguration("protocol");
    if (conf->target.ptr) {
        module = getModule(PROTOCOL, conf->target.ptr);
        if (module && getProtocol(module)->initProtocol() == WHEAT_WRONG) {
            wheatLog(WHEAT_WARNING, "init protocol failed");
            halt(1);
        }
    }
    if (!module) {
        wheatLog(WHEAT_WARNING, "find protocol %s failed", conf->target.ptr);
        halt(1);
    }
    worker->protocol = getProtocol(module);

    StatTotalClient = getStatItemByName("Total client");
    gettimeofday(&Server.cron_time, NULL);
    if (worker->worker->setup)
        worker->worker->setup();
    WorkerProcess->refresh_time = Server.cron_time.tv_sec;

    FreeClients = createAndFillPool();
    Clients = createList();
    StatBufferSize = getStatItemByName("Max buffer size");
    StatTotalRequest = getStatItemByName("Total request");
    StatFailedRequest = getStatItemByName("Total failed request");
    StatRunTime = getStatItemByName("Worker run time");

    worker->apps = arrayCreate(sizeof(struct app*), 3);
    if (!worker->apps) {
        wheatLog(WHEAT_WARNING, "array create failed");
        halt(1);
    }

    getAppsByProtocol(worker->apps, worker->protocol);
    for (i = 0; i < narray(worker->apps); i++) {
        app = *(struct app**)arrayIndex(worker->apps, i);
        if (app->initApp(worker->protocol) == WHEAT_WRONG) {
            wheatLog(WHEAT_WARNING, "init app failed %s", getModuleName(APP, app));
            halt(1);
        }
    }

    sendStatPacket(WorkerProcess);
}
Пример #7
0
static void ramcloudAppend(struct ramcloudData *d, wstr key, struct array *vals, uint32_t vlen, uint16_t flag, int append)
{
    uint32_t actual_len;
    uint64_t version;
    uint64_t len = RAMCLOUD_DEFAULT_VALUE_LEN;

again:
    wheatLog(WHEAT_DEBUG, "%s read key %s", __func__, key);

    wstr origin_val = wstrNewLen(NULL, len);
    wstr val;
    Status s = rc_read(global.client, d->table_id, key, wstrlen(key), NULL, &version, origin_val, len, &actual_len);
    if (s != STATUS_OK) {
        if (s != STATUS_OBJECT_DOESNT_EXIST) {
            wheatLog(WHEAT_WARNING, " failed to read %s: %s", key, statusToString(s));
            sliceTo(&d->storage_response, (uint8_t*)SERVER_ERROR, sizeof(SERVER_ERROR)-1);
        } else {
            sliceTo(&d->storage_response, (uint8_t*)NOT_STORED, sizeof(NOT_STORED)-1);
        }
        wstrFree(origin_val);
        return ;
    }

    while (actual_len > len) {
        wstrFree(origin_val);
        len = actual_len;
        origin_val = wstrNewLen(NULL, actual_len);
        if (origin_val == NULL) {
            sliceTo(&d->storage_response, (uint8_t*)SERVER_ERROR, sizeof(SERVER_ERROR)-1);
            wheatLog(WHEAT_WARNING, " failed to alloc memory");
            return ;
        }

        s = rc_read(global.client, d->table_id, key, wstrlen(key), NULL, &version, origin_val, len, &actual_len);
        if (s != STATUS_OK) {
            if (s != STATUS_OBJECT_DOESNT_EXIST) {
                wheatLog(WHEAT_WARNING, " failed to read %s: %s", key, statusToString(s));
                sliceTo(&d->storage_response, (uint8_t*)SERVER_ERROR, sizeof(SERVER_ERROR)-1);
            } else {
                sliceTo(&d->storage_response, (uint8_t*)NOT_STORED, sizeof(NOT_STORED)-1);
            }
            wstrFree(origin_val);
            return ;
        }
    }

    wstrupdatelen(origin_val, actual_len-FLAG_SIZE);
    if (append) {
        val = origin_val;
        // reduce flag size
    } else {
        val = wstrNewLen(NULL, vlen);
    }

    int i = 0;
    while (i < narray(vals)) {
        struct slice *slice;
        slice = arrayIndex(vals, i);
        val = wstrCatLen(val, (char*)slice->data, slice->len);
        len += slice->len;
        ++i;
    }

    if (!append) {
        val = wstrCatLen(val, origin_val, wstrlen(origin_val));
        wstrFree(origin_val);
    }
    val = wstrCatLen(val, (char*)&flag, FLAG_SIZE);

    struct RejectRules rule;
    memset(&rule, 0, sizeof(rule));
    rule.doesntExist = 1;
    rule.versionNeGiven = 1;
    rule.givenVersion = version;
    s = rc_write(global.client, d->table_id, key, wstrlen(key), val, wstrlen(val),
                        &rule, NULL);
    wstrFree(val);
    if (s != STATUS_OK) {
        if (s == STATUS_OBJECT_DOESNT_EXIST) {
            sliceTo(&d->storage_response, (uint8_t*)NOT_STORED, sizeof(NOT_STORED)-1);
            return ;
        } else if (s == STATUS_WRONG_VERSION) {
            goto again;
        }

        wheatLog(WHEAT_WARNING, " failed to write %s: %s", key, statusToString(s));
        sliceTo(&d->storage_response, (uint8_t*)SERVER_ERROR, sizeof(SERVER_ERROR)-1);
        return ;
    }
    sliceTo(&d->storage_response, (uint8_t*)STORED, sizeof(STORED)-1);
}
Пример #8
0
static void pas_SimpleAssignment(STYPE *varPtr, uint8_t assignFlags)
{
  STYPE *typePtr;
  TRACE(lstFile,"[pas_SimpleAssignment]");

  /* FORM:  <variable OR function identifer> := <expression> */

  typePtr = varPtr->sParm.v.parent;
  switch (varPtr->sKind)
    {
      /* Check if we have reduce the complex assignment to a simple
       * assignment yet
       */

    case sINT :
      if ((assignFlags & INDEXED_ASSIGNMENT) != 0)
        {
          if ((assignFlags & ADDRESS_DEREFERENCE) != 0)
            {
              pas_GenerateStackReference(opLDSX, varPtr);
              pas_Assignment(opSTI, exprInteger, varPtr, typePtr);
            } /* end if */
          else if ((assignFlags & ADDRESS_ASSIGNMENT) != 0)
            pas_Assignment(opSTSX, exprIntegerPtr, varPtr, typePtr);
          else 
            pas_Assignment(opSTSX, exprInteger, varPtr, typePtr);
        } /* end if */
      else
        {
          if ((assignFlags & ADDRESS_DEREFERENCE) != 0)
            {
              pas_GenerateStackReference(opLDS, varPtr);
              pas_Assignment(opSTI, exprInteger, varPtr, typePtr);
            } /* end if */
          else if ((assignFlags & ADDRESS_ASSIGNMENT) != 0)
            pas_Assignment(opSTS, exprIntegerPtr, varPtr, typePtr);
          else
            pas_Assignment(opSTS, exprInteger, varPtr, typePtr);
        } /* end else */
      break;
    case sCHAR :
      if ((assignFlags & INDEXED_ASSIGNMENT) != 0)
        {
          if ((assignFlags & ADDRESS_DEREFERENCE) != 0)
            {
              pas_GenerateStackReference(opLDSX, varPtr);
              pas_Assignment(opSTIB, exprChar, varPtr, typePtr);
            } /* end if */
          else if ((assignFlags & ADDRESS_ASSIGNMENT) != 0)
            pas_Assignment(opSTSX, exprCharPtr, varPtr, typePtr);
          else 
            pas_Assignment(opSTSXB, exprChar, varPtr, typePtr);
        } /* end if */
      else
        {
          if ((assignFlags & ADDRESS_DEREFERENCE) != 0)
            {
              pas_GenerateStackReference(opLDS, varPtr);
              pas_Assignment(opSTIB, exprChar, varPtr, typePtr);
            } /* end if */
          else if ((assignFlags & ADDRESS_ASSIGNMENT) != 0)
            pas_Assignment(opSTS, exprCharPtr, varPtr, typePtr);
          else
            pas_Assignment(opSTSB, exprChar, varPtr, typePtr);
        } /* end else */
      break;
    case sBOOLEAN :
      if ((assignFlags & INDEXED_ASSIGNMENT) != 0)
        {
          if ((assignFlags & ADDRESS_DEREFERENCE) != 0)
            {
              pas_GenerateStackReference(opLDSX, varPtr);
              pas_Assignment(opSTI, exprBoolean, varPtr, NULL);
            } /* end if */
          else if ((assignFlags & ADDRESS_ASSIGNMENT) != 0)
            pas_Assignment(opSTSX, exprBooleanPtr, varPtr, typePtr);
          else 
            pas_Assignment(opSTSX, exprBoolean, varPtr, NULL);
        } /* end if */
      else
        {
          if ((assignFlags & ADDRESS_DEREFERENCE) != 0)
            {
              pas_GenerateStackReference(opLDS, varPtr);
              pas_Assignment(opSTI, exprBoolean, varPtr, NULL);
            } /* end if */
          else if ((assignFlags & ADDRESS_ASSIGNMENT) != 0)
            pas_Assignment(opSTS, exprBooleanPtr, varPtr, typePtr);
          else
            pas_Assignment(opSTS, exprBoolean, varPtr, NULL);
        } /* end else */
      break;
    case sREAL         :
      if ((assignFlags & INDEXED_ASSIGNMENT) != 0)
        {
          if ((assignFlags & ADDRESS_DEREFERENCE) != 0)
            {
              pas_GenerateStackReference(opLDSX, varPtr);
              pas_LargeAssignment(opSTIM, exprReal, varPtr, typePtr);
            } /* end if */
          else if ((assignFlags & ADDRESS_ASSIGNMENT) != 0)
            pas_Assignment(opSTSX, exprRealPtr, varPtr, typePtr);
          else 
            pas_LargeAssignment(opSTSXM, exprReal, varPtr, typePtr);
        } /* end if */
      else
        {
          if ((assignFlags & ADDRESS_DEREFERENCE) != 0)
            {
              pas_GenerateStackReference(opLDS, varPtr);
              pas_LargeAssignment(opSTIM, exprReal, varPtr, typePtr);
            } /* end if */
          else if ((assignFlags & ADDRESS_ASSIGNMENT) != 0)
            pas_Assignment(opSTS, exprRealPtr, varPtr, typePtr);
          else
            pas_LargeAssignment(opSTSM, exprReal, varPtr, typePtr);
        } /* end else */
      break;
    case sSCALAR :
      if ((assignFlags & INDEXED_ASSIGNMENT) != 0)
        {
          if ((assignFlags & ADDRESS_DEREFERENCE) != 0)
            {
              pas_GenerateStackReference(opLDSX, varPtr);
              pas_Assignment(opSTI, exprScalar, varPtr, typePtr);
            } /* end if */
          else if ((assignFlags & ADDRESS_ASSIGNMENT) != 0)
            pas_Assignment(opSTSX, exprScalarPtr, varPtr, typePtr);
          else 
            pas_Assignment(opSTSX, exprScalar, varPtr, typePtr);
        } /* end if */
      else
        {
          if ((assignFlags & ADDRESS_DEREFERENCE) != 0)
            {
              pas_GenerateStackReference(opLDS, varPtr);
              pas_Assignment(opSTI, exprScalar, varPtr, typePtr);
            } /* end if */
          else if ((assignFlags & ADDRESS_ASSIGNMENT) != 0)
            pas_Assignment(opSTS, exprScalarPtr, varPtr, typePtr);
          else
            pas_Assignment(opSTS, exprScalar, varPtr, typePtr);
        } /* end else */
      break;
    case sSET_OF :
      if ((assignFlags & INDEXED_ASSIGNMENT) != 0)
        {
          if ((assignFlags & ADDRESS_DEREFERENCE) != 0)
            {
              pas_GenerateStackReference(opLDSX, varPtr);
              pas_Assignment(opSTI, exprSet, varPtr, typePtr);
            } /* end if */
          else if ((assignFlags & ADDRESS_ASSIGNMENT) != 0)
            pas_Assignment(opSTSX, exprSetPtr, varPtr, typePtr);
          else 
            pas_Assignment(opSTSX, exprSet, varPtr, typePtr);
        } /* end if */
      else
        {
          if ((assignFlags & ADDRESS_DEREFERENCE) != 0)
            {
              pas_GenerateStackReference(opLDS, varPtr);
              pas_Assignment(opSTI, exprSet, varPtr, typePtr);
            } /* end if */
          else if ((assignFlags & ADDRESS_ASSIGNMENT) != 0)
            pas_Assignment(opSTS, exprSetPtr, varPtr, typePtr);
          else
            pas_Assignment(opSTS, exprSet, varPtr, typePtr);
        } /* end else */
      break;

      /* NOPE... recurse until it becomes a simple assignment */

    case sSUBRANGE :
      varPtr->sKind = typePtr->sParm.t.subType;
      pas_SimpleAssignment(varPtr, assignFlags);
      break;

    case sRECORD :
      /* FORM: <record identifier>.<field> := <expression>
       * OR:   <record pointer identifier> := <pointer expression>
       */

      /* Check if this is a pointer to a record */

      if ((assignFlags & ADDRESS_ASSIGNMENT) != 0)
        {
          if (token == '.') error(ePOINTERTYPE);

          if ((assignFlags & INDEXED_ASSIGNMENT) != 0)
            pas_Assignment(opSTSX, exprRecordPtr, varPtr, typePtr);
          else
            pas_Assignment(opSTS, exprRecordPtr, varPtr, typePtr);
        } /* end if */
      else if (((assignFlags & ADDRESS_DEREFERENCE) != 0) &&
               ((assignFlags & VAR_PARM_ASSIGNMENT) == 0))
        error(ePOINTERTYPE);

      /* Check if a period separates the RECORD identifier from the
       * record field identifier
       */

      else if (token == '.')
        {
          /* Skip over the period */

          getToken();

          /* Verify that a field identifier associated with this record
           * follows the period.
           */

          if ((token != sRECORD_OBJECT) ||
              (tknPtr->sParm.r.record != typePtr))
            error(eRECORDOBJECT);
          else
            {
              /* Modify the variable so that it has the characteristics of the
               * the field but with level and offset associated with the record
               */

              typePtr                 = tknPtr->sParm.r.parent;
              varPtr->sKind           = typePtr->sParm.t.type;
              varPtr->sParm.v.parent  = typePtr;

              /* Special case:  The record is a VAR parameter. */

              if (assignFlags == (INDEXED_ASSIGNMENT | ADDRESS_DEREFERENCE | VAR_PARM_ASSIGNMENT))
                {
                  pas_GenerateDataOperation(opPUSH, tknPtr->sParm.r.offset);
                  pas_GenerateSimple(opADD);
                } /* end if */
              else
                varPtr->sParm.v.offset += tknPtr->sParm.r.offset;

              getToken();
              pas_SimpleAssignment(varPtr, assignFlags);

            } /* end else if */
        } /* end else */

      /* It must be a RECORD assignment */

      else
        {
          /* Special case:  The record is a VAR parameter. */

          if (assignFlags == (INDEXED_ASSIGNMENT | ADDRESS_DEREFERENCE | VAR_PARM_ASSIGNMENT))
            {
              pas_GenerateStackReference(opLDS, varPtr);
              pas_GenerateSimple(opADD);
              pas_LargeAssignment(opSTIM, exprRecord, varPtr, typePtr);
            } /* end if */
          else
            pas_LargeAssignment(opSTSM, exprRecord, varPtr, typePtr);
        } /* end else */
      break;

    case sRECORD_OBJECT :
      /* FORM: <field> := <expression>
       * NOTE:  This must have been preceeded with a WITH statement
       * defining the RECORD type
       */

      if (!withRecord.parent)
        error(eINVTYPE);
      else if ((assignFlags && (ADDRESS_DEREFERENCE | ADDRESS_ASSIGNMENT)) != 0)
        error(ePOINTERTYPE);
      else if ((assignFlags && INDEXED_ASSIGNMENT) != 0)
        error(eARRAYTYPE);

      /* Verify that a field identifier is associated with the RECORD
       * specified by the WITH statement.
       */

      else if (varPtr->sParm.r.record != withRecord.parent)
        error(eRECORDOBJECT);

      else
        {
          int16_t tempOffset;

          /* Now there are two cases to consider:  (1) the withRecord is a
           * pointer to a RECORD, or (2) the withRecord is the RECORD itself
           */

          if (withRecord.pointer)
            {
              /* If the pointer is really a VAR parameter, then other syntax
               * rules will apply
               */

              if (withRecord.varParm)
                assignFlags |= (INDEXED_ASSIGNMENT | ADDRESS_DEREFERENCE | VAR_PARM_ASSIGNMENT);
              else
                assignFlags |= (INDEXED_ASSIGNMENT | ADDRESS_DEREFERENCE);

              pas_GenerateDataOperation(opPUSH, (varPtr->sParm.r.offset + withRecord.index));
              tempOffset     = withRecord.offset;
            } /* end if */
          else
            {
              tempOffset   = varPtr->sParm.r.offset + withRecord.offset;
            } /* end else */

          /* Modify the variable so that it has the characteristics of the
           * the field but with level and offset associated with the record
           * NOTE:  We have to be careful here because the structure
           * associated with sRECORD_OBJECT is not the same as for
           * variables!
           */

          typePtr                 = varPtr->sParm.r.parent;

          varPtr->sKind           = typePtr->sParm.t.type;
          varPtr->sLevel          = withRecord.level;
          varPtr->sParm.v.size    = typePtr->sParm.t.asize;
          varPtr->sParm.v.offset  = tempOffset;
          varPtr->sParm.v.parent  = typePtr;

          pas_SimpleAssignment(varPtr, assignFlags);

        } /* end else */
      break;

    case sPOINTER :
      /* FORM: <pointer identifier>^ := <expression>
       * OR:   <pointer identifier> := <pointer expression>
       */

      if (token == '^') /* value assignment? */
        {
          getToken();
          assignFlags |= ADDRESS_DEREFERENCE;
        } /* end if */
      else
        assignFlags |= ADDRESS_ASSIGNMENT;

      varPtr->sKind = typePtr->sParm.t.type;
      pas_SimpleAssignment(varPtr, assignFlags);
      break;

    case sVAR_PARM :
      if (assignFlags != 0) error(eVARPARMTYPE);
      assignFlags |= (ADDRESS_DEREFERENCE | VAR_PARM_ASSIGNMENT);

      varPtr->sKind = typePtr->sParm.t.type;
      pas_SimpleAssignment(varPtr, assignFlags);
      break;

    case sARRAY :
      /* FORM: <array identifier> := <expression>
       * OR:   <pointer array identifier>[<index>]^ := <expression>
       * OR:   <pointer array identifier>[<index>] := <pointer expression>
       * OR:   <record array identifier>[<index>].<field identifier> := <expression>
       * OR:   etc., etc., etc.
       */

      if (assignFlags != 0) error(eARRAYTYPE);
      assignFlags |= INDEXED_ASSIGNMENT;

      arrayIndex(typePtr->sParm.t.asize);
      varPtr->sKind        = typePtr->sParm.t.type;
      varPtr->sParm.v.size = typePtr->sParm.t.asize;
      pas_SimpleAssignment(varPtr, assignFlags);
      break;

    default :
      error(eINVTYPE);
      break;

    }
}