00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <complex.h>
00021 #include <sys/time.h>
00022 #include "jsoc_main.h"
00023 #include "drms_types.h"
00024 #include "fftw3.h"
00025
00026 #define PRINTJSD 0
00027 #define DEBUGMSGS 0
00028
00029 char *module_name = "demo_td08062007";
00030
00031 #define kRecSetIn "recsin"
00032 #define kDSOut "dsout"
00033 #define kOutSeries "su_arta.TestDemoTD"
00034
00035 ModuleArgs_t module_args[] =
00036 {
00037 {ARG_STRING, kRecSetIn, "", "Input data series."},
00038 {ARG_STRING, kDSOut, kOutSeries, "Output data series."},
00039 {ARG_END}
00040 };
00041
00042 typedef enum
00043 {
00044 kDemoError_Success,
00045 kDemoError_CouldntCheckSeries,
00046 kDemoError_CouldntCreateSeries,
00047 kDemoError_InputIncompatibleWithSeries,
00048 kDemoError_CouldntCreateRecord,
00049 kDemoError_SegmentNotFound,
00050 kDemoError_UnsupportedDimensionality,
00051 kDemoError_UnsupportedDataType,
00052 kDemoError_BadParameter,
00053 kDemoError_CouldntCreateArray,
00054 kDemoError_UnknownSeries,
00055 kDemoError_BadQuerySyntax,
00056 kDemoError_DrmsOpen
00057 } DemoError_t;
00058
00059 typedef enum
00060 {
00061 kOutputSeriesDisp_Unknown,
00062 kOutputSeriesDisp_DoesntExist,
00063 kOutputSeriesDisp_Exists,
00064 } OutputSeriesDisp_t;
00065
00066
00067
00068 #if PRINTJSD
00069 void drms_keyword_print_jsd(DRMS_Keyword_t *key) {
00070 printf("Keyword:%s",key->info->name);
00071 if (key->info->islink) {
00072 printf(", link, %s, %s, %s\n", key->info->linkname,
00073 key->info->target_key,
00074 key->info->description);
00075 } else {
00076 printf(", %s", drms_type2str(key->info->type));
00077 printf(", %s", drms_keyword_recscopestr(key, NULL));
00078 if (key->info->per_segment)
00079 printf(", segment");
00080 else
00081 printf(", record");
00082 printf(", ");
00083 if (key->info->type == DRMS_TYPE_STRING) {
00084 char qf[DRMS_MAXFORMATLEN+2];
00085 sprintf(qf, "\"%s\"", key->info->format);
00086 printf(qf, key->value.string_val);
00087 }
00088 else
00089 drms_keyword_printval(key);
00090 if (key->info->unit[0] != ' ') {
00091 printf(", %s, %s, \"%s\"", key->info->format,
00092 key->info->unit,
00093 key->info->description);
00094 } else {
00095 printf(", %s, none, \"%s\"", key->info->format,
00096 key->info->description);
00097 }
00098 }
00099 printf("\n");
00100 }
00101
00102 void drms_segment_print_jsd(DRMS_Segment_t *seg) {
00103 int i;
00104 printf("Data: %s, ", seg->info->name);
00105 if (seg->info->islink) {
00106 printf("link, %s, %s", seg->info->linkname, seg->info->target_seg);
00107 if (seg->info->naxis) {
00108 printf(", %d", seg->info->naxis);
00109 printf(", %d", seg->axis[0]);
00110 for (i=1; i<seg->info->naxis; i++) {
00111 printf(", %d", seg->axis[i]);
00112 }
00113 }
00114 } else {
00115 switch(seg->info->scope)
00116 {
00117 case DRMS_CONSTANT:
00118 printf("constant");
00119 break;
00120 case DRMS_VARIABLE:
00121 printf("variable");
00122 break;
00123 case DRMS_VARDIM:
00124 printf("vardim");
00125 break;
00126 default:
00127 printf("Illegal value: %d", (int)seg->info->scope);
00128 }
00129 printf(", %s, %d", drms_type2str(seg->info->type), seg->info->naxis);
00130 if (seg->info->naxis) {
00131 printf(", %d", seg->axis[0]);
00132 for (i=1; i<seg->info->naxis; i++) {
00133 printf(", %d", seg->axis[i]);
00134 }
00135 }
00136 printf(", %s, ", seg->info->unit);
00137 switch(seg->info->protocol)
00138 {
00139 case DRMS_GENERIC:
00140 printf("generic");
00141 break;
00142 case DRMS_BINARY:
00143 printf("binary");
00144 break;
00145 case DRMS_BINZIP:
00146 printf("binzip");
00147 break;
00148 case DRMS_FITZ:
00149 printf("fitz");
00150 break;
00151 case DRMS_FITS:
00152 printf("fits");
00153 break;
00154 case DRMS_MSI:
00155 printf("msi");
00156 break;
00157 case DRMS_TAS:
00158 printf("tas");
00159 if (seg->info->naxis) {
00160 printf(", %d", seg->blocksize[0]);
00161 for (i=1; i<seg->info->naxis; i++)
00162 printf(", %d", seg->blocksize[i]);
00163 }
00164 break;
00165 default:
00166 printf("Illegal value: %d", (int)seg->info->protocol);
00167 }
00168 }
00169 printf(", \"%s\"\n", seg->info->description);
00170 }
00171
00172 void drms_link_print_jsd(DRMS_Link_t *link) {
00173 printf("Link: %s, %s, ", link->info->name, link->info->target_series);
00174 if (link->info->type == STATIC_LINK)
00175 printf("static");
00176 else
00177 printf("dynamic");
00178 printf(", \"%s\"\n", link->info->description);
00179 }
00180
00181 void print_jsd(DRMS_Record_t *rec) {
00182 const int fwidth=17;
00183 int i;
00184 HIterator_t hit;
00185 DRMS_Link_t *link;
00186 DRMS_Keyword_t *key;
00187 DRMS_Segment_t *seg;
00188
00189 printf("#=====General Series Information=====\n");
00190 printf("%-*s\t%s\n",fwidth,"Seriesname:",rec->seriesinfo->seriesname);
00191 printf("%-*s\t\"%s\"\n",fwidth,"Author:",rec->seriesinfo->author);
00192 printf("%-*s\t%s\n",fwidth,"Owner:",rec->seriesinfo->owner);
00193 printf("%-*s\t%d\n",fwidth,"Unitsize:",rec->seriesinfo->unitsize);
00194 printf("%-*s\t%d\n",fwidth,"Archive:",rec->seriesinfo->archive);
00195 printf("%-*s\t%d\n",fwidth,"Retention:",rec->seriesinfo->retention);
00196 printf("%-*s\t%d\n",fwidth,"Tapegroup:",rec->seriesinfo->tapegroup);
00197 if (rec->seriesinfo->pidx_num) {
00198 printf("%-*s\t%s",fwidth,"Index:",rec->seriesinfo->pidx_keywords[0]->info->name);
00199 for (i=1; i<rec->seriesinfo->pidx_num; i++)
00200 printf(", %s", (rec->seriesinfo->pidx_keywords[i])->info->name);
00201 printf("\n");
00202 }
00203 printf("%-*s\t%s\n",fwidth,"Description:",rec->seriesinfo->description);
00204 printf("\n#=====Links=====\n");
00205 hiter_new(&hit, &rec->links);
00206 while( (link = (DRMS_Link_t *)hiter_getnext(&hit)) )
00207 drms_link_print_jsd(link);
00208
00209 printf("\n#=====Keywords=====\n");
00210 hiter_new(&hit, &rec->keywords);
00211 while( (key = (DRMS_Keyword_t *)hiter_getnext(&hit)) )
00212 drms_keyword_print_jsd(key);
00213
00214 printf("\n#=====Segments=====\n");
00215 hiter_new(&hit, &rec->segments);
00216 while( (seg = (DRMS_Segment_t *)hiter_getnext(&hit)) )
00217 drms_segment_print_jsd(seg);
00218 }
00219 #endif // PRINTJSD
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229 static int CreateOutSeries(DRMS_Env_t *env, DRMS_Record_t *rec)
00230 {
00231 int error = kDemoError_CouldntCreateSeries;
00232 int status = DRMS_SUCCESS;
00233
00234 DRMS_Record_t *sourceRec = drms_template_record(env, rec->seriesinfo->seriesname, &status);
00235 DRMS_Segment_t *segproto = NULL;
00236
00237 if (sourceRec)
00238 {
00239 DRMS_Record_t *prototype = drms_create_recproto(sourceRec, &status);
00240
00241 if (prototype)
00242 {
00243 DRMS_SegmentDimInfo_t di;
00244
00245 if (hcon_size(&(prototype->segments)) != 1)
00246 {
00247 XASSERT(0);
00248 fprintf(stderr,
00249 "Warning: more than one segment in input series; using first segment.\n");
00250 }
00251
00252 if ((segproto = drms_segment_lookupnum(prototype, 0)) != NULL)
00253 {
00254 if (segproto->info->naxis != 3)
00255 {
00256 error = kDemoError_UnsupportedDimensionality;
00257 }
00258
00259 else
00260 {
00261 if (segproto->info->protocol == DRMS_DSDS ||
00262 segproto->info->protocol == DRMS_LOCAL)
00263 {
00264
00265 segproto->info->protocol = DRMS_FITS;
00266 }
00267 else
00268 {
00269
00270 }
00271
00272 if (segproto->info->type != DRMS_TYPE_DOUBLE)
00273 {
00274 segproto->info->type = DRMS_TYPE_FLOAT;
00275 }
00276
00277 drms_segment_getdims(segproto, &di);
00278 di.naxis = 2;
00279 di.axis[0] = (segproto->axis)[1] / 2;
00280 di.axis[1] = (segproto->axis)[2] / 2;
00281 drms_segment_setdims(segproto, &di);
00282
00283 #if PRINTJSD
00284 print_jsd(prototype);
00285 #endif
00286
00287 status = drms_create_series_fromprototype(&prototype, kOutSeries, 0);
00288 if (status == DRMS_SUCCESS)
00289 {
00290 error = kDemoError_Success;
00291 }
00292 }
00293 }
00294 else
00295 {
00296 drms_destroy_recproto(&prototype);
00297 }
00298 }
00299 }
00300
00301 return error;
00302 }
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313 static int CheckCompat(DRMS_Env_t *env, DRMS_Record_t *rec, const char *dsout)
00314 {
00315 int compat = 0;
00316 int status = DRMS_SUCCESS;
00317
00318 DRMS_Record_t *prototype = drms_create_recproto(rec, &status);
00319 DRMS_Segment_t *segproto = NULL;
00320 HContainer_t *matchSegNames = NULL;
00321
00322 if (prototype)
00323 {
00324 if ((segproto = drms_segment_lookupnum(prototype, 0)) != NULL)
00325 {
00326 DRMS_SegmentDimInfo_t di;
00327
00328 if (segproto->info->protocol == DRMS_DSDS ||
00329 segproto->info->protocol == DRMS_LOCAL)
00330 {
00331
00332 segproto->info->protocol = DRMS_FITS;
00333 }
00334 else
00335 {
00336
00337 }
00338
00339 if (segproto->info->type != DRMS_TYPE_DOUBLE)
00340 {
00341 segproto->info->type = DRMS_TYPE_FLOAT;
00342 }
00343
00344
00345
00346 drms_segment_getdims(segproto, &di);
00347 di.naxis = 2;
00348 di.axis[0] = (segproto->axis)[1] / 2;
00349 di.axis[1] = (segproto->axis)[2] / 2;
00350 drms_segment_setdims(segproto, &di);
00351
00352 matchSegNames = (HContainer_t *)malloc(sizeof(HContainer_t));
00353 XASSERT(matchSegNames != NULL);
00354 compat = drms_series_checkrecordcompat(env,
00355 dsout,
00356 prototype,
00357 matchSegNames,
00358 &status);
00359
00360 hcon_destroy(&matchSegNames);
00361 drms_destroy_recproto(&prototype);
00362
00363 if (!compat)
00364 {
00365 fprintf(stderr,
00366 "Output series %s is not compatible with output data.\n",
00367 dsout);
00368 }
00369 }
00370 }
00371
00372 return compat;
00373 }
00374
00375
00376
00377
00378
00379
00380
00381
00382 DemoError_t Crunch(DRMS_Array_t *arrin, DRMS_Array_t **arrout)
00383 {
00384 DemoError_t error = kDemoError_Success;
00385 int status = DRMS_SUCCESS;
00386
00387 if (arrin && arrout)
00388 {
00389 long long arrsize = drms_array_count(arrin);
00390 DRMS_Type_t type = arrin->type;
00391 int laxis1 = drms_array_nth_axis(arrin, 0);
00392 int laxis2 = drms_array_nth_axis(arrin, 1);
00393 int laxis3 = drms_array_nth_axis(arrin, 2);
00394 int axisout[2] = {laxis2 / 2, laxis3 / 2};
00395 long long nElem = drms_array_count(arrin);
00396
00397 *arrout = drms_array_create(type,
00398 2,
00399 axisout,
00400 NULL,
00401 &status);
00402
00403 if (*arrout)
00404 {
00405 fftwf_plan p;
00406 fftwf_complex datc[laxis3][laxis1][laxis1 / 2 + 1];
00407
00408
00409 long long iData;
00410
00411 if (type == DRMS_TYPE_FLOAT)
00412 {
00413 float *pDataIn = arrin->data;
00414
00415 for (iData = 0; iData < nElem; iData++)
00416 {
00417 pDataIn[iData] = pDataIn[iData] / (float)arrsize;
00418 }
00419 }
00420 else if (type == DRMS_TYPE_DOUBLE)
00421 {
00422 double *pDataIn = arrin->data;
00423
00424 for (iData = 0; iData < nElem; iData++)
00425 {
00426 pDataIn[iData] = pDataIn[iData] / (double)arrsize;
00427 }
00428 }
00429
00430 p = fftwf_plan_dft_r2c_3d(laxis3,
00431 laxis2,
00432 laxis1,
00433 arrin->data,
00434 &datc[0][0][0],
00435 FFTW_ESTIMATE);
00436
00437 fftwf_execute(p);
00438 fftwf_destroy_plan(p);
00439
00440 int i;
00441 int j;
00442 int k;
00443 int ii;
00444
00445 int iLim = laxis3 / 2;
00446 int jLim = laxis2 / 2;
00447 int kLim = laxis1 / 2;
00448
00449 memset((*arrout)->data, 0, drms_array_size(*arrout));
00450
00451 if (type == DRMS_TYPE_FLOAT)
00452 {
00453 float *power = (*arrout)->data;
00454
00455 for (j = 0; j < jLim; j++)
00456 {
00457 for (k = 0; k < kLim; k++)
00458 {
00459 ii = (int)(sqrtf(powf((float)j, 2.0) + powf((float)k, 2.0)));
00460
00461 if (ii < jLim)
00462 {
00463 for (i = 0; i < iLim; i++)
00464 {
00465 power[i * axisout[0] + ii] +=
00466 powf(cabsf(datc[i][j][k]), 2.0);
00467 }
00468 }
00469 }
00470 }
00471 }
00472 else if(type == DRMS_TYPE_DOUBLE)
00473 {
00474 double *power = (*arrout)->data;
00475
00476 for (j = 0; j < jLim; j++)
00477 {
00478 for (k = 0; k < kLim; k++)
00479 {
00480 ii = (int)(sqrtf(powf((float)j, 2.0) + powf((float)k, 2.0)));
00481
00482 if (ii < jLim)
00483 {
00484 for (i = 0; i < iLim; i++)
00485 {
00486 power[i * axisout[0] + ii] +=
00487 pow(cabs(datc[i][j][k]), 2.0);
00488 }
00489 }
00490 }
00491 }
00492 }
00493 }
00494 else
00495 {
00496 error = kDemoError_CouldntCreateArray;
00497 }
00498 }
00499 else
00500 {
00501 error = kDemoError_BadParameter;
00502 }
00503
00504 return error;
00505 }
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516 void LogTime(int clear, const char *msg)
00517 {
00518 static double stTime = 0.0;
00519 struct timeval tv;
00520 double newTime = 0.0;
00521 double elapsed = 0.0;
00522
00523 gettimeofday(&tv, NULL);
00524 newTime = (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
00525
00526 if (clear)
00527 {
00528 stTime = newTime;
00529 elapsed = 0.0;
00530 }
00531 else
00532 {
00533 elapsed = newTime - stTime;
00534 fprintf(stdout,
00535 "%s: done (%.3g seconds elapsed)\n",
00536 msg,
00537 elapsed);
00538 fflush(stdout);
00539 }
00540 }
00541
00542
00543
00544
00545
00546 int DoIt(void)
00547 {
00548 int status = DRMS_SUCCESS;
00549 DemoError_t error = kDemoError_Success;
00550 char *inRecQuery = cmdparams_get_str(&cmdparams, kRecSetIn, NULL);
00551 char rquery[DRMS_MAXQUERYLEN];
00552 char *dsout = cmdparams_get_str(&cmdparams, kDSOut, NULL);
00553 DRMS_RecordSet_t *inRecSet = NULL;
00554 DRMS_RecordSetType_t rqueryType;
00555 OutputSeriesDisp_t disp;
00556
00557 rqueryType = drms_record_getquerytype(inRecQuery);
00558
00559 if (rqueryType == kRecordSetType_DSDS)
00560 {
00561 fprintf(stdout, "Fetching records from DSDS");
00562 fflush(stdout);
00563 LogTime(1, NULL);
00564 }
00565
00566 drms_series_exists(drms_env, dsout, &status);
00567 disp = (status == DRMS_ERROR_UNKNOWNSERIES) ? kOutputSeriesDisp_DoesntExist :
00568 ((status != DRMS_SUCCESS) ? kOutputSeriesDisp_Unknown : kOutputSeriesDisp_Exists);
00569
00570 if (disp == kOutputSeriesDisp_Unknown)
00571 {
00572 error = kDemoError_CouldntCheckSeries;
00573 }
00574 else
00575 {
00576 if (disp == kOutputSeriesDisp_Exists &&
00577 !strchr(inRecQuery, '[') &&
00578 rqueryType == kRecordSetType_PlainFile)
00579 {
00580
00581
00582 int nPKeys = 0;
00583 char **pkArray = NULL;
00584
00585 pkArray = drms_series_createpkeyarray(drms_env, dsout, &nPKeys, &status);
00586 if (status == DRMS_SUCCESS)
00587 {
00588 char *buf = (char *)malloc(sizeof(char) * DRMS_MAXKEYNAMELEN * nPKeys + 32);
00589 *buf = '\0';
00590 int iKey;
00591
00592 for (iKey = 0; iKey < nPKeys; iKey++)
00593 {
00594 if (!iKey == 0)
00595 {
00596 strcat(buf, ",");
00597 }
00598
00599 strcat(buf, pkArray[iKey]);
00600 }
00601
00602 snprintf(rquery, sizeof(rquery), "%s[%s]", inRecQuery, buf);
00603
00604 if (buf)
00605 {
00606 free(buf);
00607 }
00608
00609 drms_series_destroypkeyarray(&pkArray, nPKeys);
00610 }
00611 else
00612 {
00613 error = kDemoError_CouldntCheckSeries;
00614 }
00615 }
00616 else
00617 {
00618
00619 snprintf(rquery, sizeof(rquery), "%s", inRecQuery);
00620 }
00621
00622 if (!error)
00623 {
00624 inRecSet = drms_open_records(drms_env, rquery, &status);
00625
00626 if (rqueryType == kRecordSetType_DSDS)
00627 {
00628 LogTime(0, "");
00629 }
00630
00631 if (status == DRMS_ERROR_UNKNOWNSERIES)
00632 {
00633 error = kDemoError_UnknownSeries;
00634 fprintf(stderr, "Unknown series.\n");
00635 }
00636 else if (status == DRMS_ERROR_INVALIDDATA)
00637 {
00638 error = kDemoError_BadQuerySyntax;
00639 }
00640 else if (status == DRMS_INEXACT)
00641 {
00642 error = kDemoError_BadQuerySyntax;
00643 fprintf(stderr, "Error in drms_open_records(), err num %d.\n"
00644 "Probably bad series query syntax, or invalid local file/directory name.\n",
00645 status);
00646 }
00647 else if (status != DRMS_SUCCESS)
00648 {
00649 error = kDemoError_DrmsOpen;
00650 fprintf(stderr, "Error in drms_open_records(), err num %d.\n"
00651 "Probably bad series query syntax, or invalid local file/directory name.\n",
00652 status);
00653 }
00654 }
00655 }
00656
00657 if (!error)
00658 {
00659 int nRecs = inRecSet->n;
00660 int iRec;
00661
00662
00663 DRMS_Record_t *recout = NULL;
00664 DRMS_Segment_t *segout = NULL;
00665 DRMS_Segment_t *segin = NULL;
00666
00667 if (nRecs > 0)
00668 {
00669 if (disp == kOutputSeriesDisp_DoesntExist)
00670 {
00671 #if DEBUGMSGS
00672 fprintf(stdout, "env cache before\n\n");
00673 hcon_print(&(drms_env->series_cache));
00674 #endif
00675
00676 if (CreateOutSeries(drms_env, inRecSet->records[0]))
00677 {
00678 error = kDemoError_CouldntCreateSeries;
00679 }
00680
00681 #if DEBUGMSGS
00682 fprintf(stdout, "env cache after\n\n");
00683 hcon_print(&(drms_env->series_cache));
00684 #endif
00685 }
00686 }
00687
00688 for (iRec = 0; !error && iRec < nRecs; iRec++)
00689 {
00690 DRMS_Record_t *rec = inRecSet->records[iRec];
00691 if (rec)
00692 {
00693 fprintf(stdout, "Record %d\n", iRec);
00694 fflush(stdout);
00695
00696
00697 if (!CheckCompat(drms_env, rec, dsout))
00698 {
00699 error = kDemoError_InputIncompatibleWithSeries;
00700 }
00701
00702 if (!error)
00703 {
00704 segin = drms_segment_lookupnum(rec, 0);
00705 if (segin)
00706 {
00707 DRMS_Array_t *arrin = NULL;
00708 DRMS_Array_t *arrout = NULL;
00709 DRMS_Type_t outType =
00710 (segin->info->type != DRMS_TYPE_DOUBLE) ? DRMS_TYPE_FLOAT: DRMS_TYPE_DOUBLE;
00711
00712 fprintf(stdout, " reading data");
00713 fflush(stdout);
00714 LogTime(1, NULL);
00715
00716 arrin = drms_segment_read(segin, outType, &status);
00717
00718 LogTime(0, "");
00719
00720 if (arrin)
00721 {
00722 int naxis = drms_array_naxis(arrin);
00723
00724 if (naxis != 3)
00725 {
00726 error = kDemoError_UnsupportedDimensionality;
00727 }
00728
00729 if (error == kDemoError_Success)
00730 {
00731 DRMS_RecordSet_t *rs = NULL;
00732
00733 fprintf(stdout, " processing data");
00734 fflush(stdout);
00735 LogTime(1, NULL);
00736
00737 error = Crunch(arrin, &arrout);
00738
00739 LogTime(0, "");
00740
00741 if (error == kDemoError_Success)
00742 {
00743 rs = drms_create_records(drms_env,
00744 1,
00745 dsout,
00746 DRMS_PERMANENT,
00747 &status);
00748
00749 if (status != DRMS_SUCCESS)
00750 {
00751 error = kDemoError_CouldntCreateRecord;
00752 }
00753 }
00754
00755 if (!error)
00756 {
00757 recout = rs->records[0];
00758 }
00759
00760 if (recout)
00761 {
00762 DRMS_Keyword_t *key = NULL;
00763 segout = drms_segment_lookupnum(recout, 0);
00764 if (segout)
00765 {
00766 HIterator_t *hit = hiter_create(&(rec->keywords));
00767 if (hit)
00768 {
00769 while ((key = hiter_getnext(hit)) != NULL)
00770 {
00771 status = drms_setkey(recout,
00772 key->info->name,
00773 key->info->type,
00774 &(key->value));
00775 }
00776
00777 hiter_destroy(&hit);
00778 }
00779
00780 drms_segment_write(segout, arrout, 0);
00781 }
00782
00783 drms_close_records(rs, DRMS_INSERT_RECORD);
00784 }
00785
00786 drms_free_array(arrin);
00787 }
00788 }
00789 }
00790 else
00791 {
00792 error = kDemoError_SegmentNotFound;
00793 }
00794 }
00795 }
00796 }
00797
00798 if (inRecSet)
00799 {
00800 drms_close_records(inRecSet, DRMS_FREE_RECORD);
00801 }
00802 }
00803
00804 return error;
00805 }