00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 #include "TextBuffer.h"
00025 #include "Tokenizer.h"
00026 #include "ink_defs.h"
00027 #include "ink_string.h"
00028 
00029 #include "P_RecFile.h"
00030 #include "P_RecUtils.h"
00031 #include "P_RecMessage.h"
00032 #include "P_RecCore.h"
00033 
00034 RecModeT g_mode_type = RECM_NULL;
00035 
00036 
00037 
00038 
00039 
00040 static int
00041 send_reset_message(RecRecord * record)
00042 {
00043   RecMessage *m;
00044 
00045   rec_mutex_acquire(&(record->lock));
00046   m = RecMessageAlloc(RECG_RESET);
00047   m = RecMessageMarshal_Realloc(m, record);
00048   RecDebug(DL_Note, "[send] RECG_RESET [%d bytes]", sizeof(RecMessageHdr) + m->o_write - m->o_start);
00049   RecMessageSend(m);
00050   RecMessageFree(m);
00051   rec_mutex_release(&(record->lock));
00052 
00053   return REC_ERR_OKAY;
00054 }
00055 
00056 
00057 
00058 
00059 
00060 static int
00061 send_set_message(RecRecord * record)
00062 {
00063   RecMessage *m;
00064 
00065   rec_mutex_acquire(&(record->lock));
00066   m = RecMessageAlloc(RECG_SET);
00067   m = RecMessageMarshal_Realloc(m, record);
00068   RecDebug(DL_Note, "[send] RECG_SET [%d bytes]", sizeof(RecMessageHdr) + m->o_write - m->o_start);
00069   RecMessageSend(m);
00070   RecMessageFree(m);
00071   rec_mutex_release(&(record->lock));
00072 
00073   return REC_ERR_OKAY;
00074 }
00075 
00076 
00077 
00078 
00079 
00080 int
00081 send_register_message(RecRecord * record)
00082 {
00083   RecMessage *m;
00084 
00085   rec_mutex_acquire(&(record->lock));
00086   m = RecMessageAlloc(RECG_REGISTER);
00087   m = RecMessageMarshal_Realloc(m, record);
00088   RecDebug(DL_Note, "[send] RECG_REGISTER [%d bytes]", sizeof(RecMessageHdr) + m->o_write - m->o_start);
00089   RecMessageSend(m);
00090   RecMessageFree(m);
00091   rec_mutex_release(&(record->lock));
00092 
00093   return REC_ERR_OKAY;
00094 }
00095 
00096 
00097 
00098 
00099 
00100 int
00101 send_push_message()
00102 {
00103   RecRecord *r;
00104   RecMessage *m;
00105   int i, num_records;
00106   bool send_msg = false;
00107 
00108   m = RecMessageAlloc(RECG_PUSH);
00109   num_records = g_num_records;
00110   for (i = 0; i < num_records; i++) {
00111     r = &(g_records[i]);
00112     rec_mutex_acquire(&(r->lock));
00113     if (i_am_the_record_owner(r->rec_type)) {
00114       if (r->sync_required & REC_PEER_SYNC_REQUIRED) {
00115         m = RecMessageMarshal_Realloc(m, r);
00116         r->sync_required &= ~REC_PEER_SYNC_REQUIRED;
00117         send_msg = true;
00118       }
00119     }
00120     rec_mutex_release(&(r->lock));
00121   }
00122   if (send_msg) {
00123     RecDebug(DL_Note, "[send] RECG_PUSH [%d bytes]", sizeof(RecMessageHdr) + m->o_write - m->o_start);
00124     RecMessageSend(m);
00125   }
00126   RecMessageFree(m);
00127 
00128   return REC_ERR_OKAY;
00129 }
00130 
00131 
00132 
00133 
00134 
00135 int
00136 send_pull_message(RecMessageT msg_type)
00137 {
00138   RecRecord *r;
00139   RecMessage *m;
00140   int i, num_records;
00141 
00142   m = RecMessageAlloc(msg_type);
00143   switch (msg_type) {
00144 
00145   case RECG_PULL_REQ:
00146     
00147     
00148     RecDebug(DL_Note, "[send] RECG_PULL_REQ [%d bytes]", sizeof(RecMessageHdr) + m->o_write - m->o_start);
00149     break;
00150 
00151   case RECG_PULL_ACK:
00152     
00153     
00154     
00155     num_records = g_num_records;
00156     for (i = 0; i < num_records; i++) {
00157       r = &(g_records[i]);
00158       if (i_am_the_record_owner(r->rec_type) ||
00159           (REC_TYPE_IS_STAT(r->rec_type) && !(r->registered)) ||
00160           (REC_TYPE_IS_STAT(r->rec_type) && (r->stat_meta.persist_type == RECP_NON_PERSISTENT))) {
00161         rec_mutex_acquire(&(r->lock));
00162         m = RecMessageMarshal_Realloc(m, r);
00163         r->sync_required &= ~REC_PEER_SYNC_REQUIRED;
00164         rec_mutex_release(&(r->lock));
00165       }
00166     }
00167     RecDebug(DL_Note, "[send] RECG_PULL_ACK [%d bytes]", sizeof(RecMessageHdr) + m->o_write - m->o_start);
00168     break;
00169 
00170   default:
00171     RecMessageFree(m);
00172     return REC_ERR_FAIL;
00173 
00174   }
00175 
00176   RecMessageSend(m);
00177   RecMessageFree(m);
00178 
00179   return REC_ERR_OKAY;
00180 }
00181 
00182 
00183 
00184 
00185 
00186 int
00187 recv_message_cb(RecMessage * msg, RecMessageT msg_type, void *)
00188 {
00189   RecRecord *r;
00190   RecMessageItr itr;
00191 
00192   switch (msg_type) {
00193 
00194   case RECG_SET:
00195 
00196     RecDebug(DL_Note, "[recv] RECG_SET [%d bytes]", sizeof(RecMessageHdr) + msg->o_end - msg->o_start);
00197     if (RecMessageUnmarshalFirst(msg, &itr, &r) != REC_ERR_FAIL) {
00198       do {
00199         if (REC_TYPE_IS_STAT(r->rec_type)) {
00200           RecSetRecord(r->rec_type, r->name, r->data_type, &(r->data), &(r->stat_meta.data_raw));
00201         } else {
00202           RecSetRecord(r->rec_type, r->name, r->data_type, &(r->data), NULL);
00203         }
00204       } while (RecMessageUnmarshalNext(msg, &itr, &r) != REC_ERR_FAIL);
00205     }
00206     break;
00207 
00208   case RECG_RESET:
00209 
00210     RecDebug(DL_Note, "[recv] RECG_RESET [%d bytes]", sizeof(RecMessageHdr) + msg->o_end - msg->o_start);
00211     if (RecMessageUnmarshalFirst(msg, &itr, &r) != REC_ERR_FAIL) {
00212       do {
00213         if (REC_TYPE_IS_STAT(r->rec_type)) {
00214           RecResetStatRecord(r->name);
00215         } else {
00216           RecSetRecord(r->rec_type, r->name, r->data_type, &(r->data), NULL);
00217         }
00218       } while (RecMessageUnmarshalNext(msg, &itr, &r) != REC_ERR_FAIL);
00219     }
00220     break;
00221 
00222   case RECG_REGISTER:
00223     RecDebug(DL_Note, "[recv] RECG_REGISTER [%d bytes]", sizeof(RecMessageHdr) + msg->o_end - msg->o_start);
00224     if (RecMessageUnmarshalFirst(msg, &itr, &r) != REC_ERR_FAIL) {
00225       do {
00226         if (REC_TYPE_IS_STAT(r->rec_type)) {
00227           RecRegisterStat(r->rec_type, r->name, r->data_type, r->data_default, r->stat_meta.persist_type);
00228         } else if (REC_TYPE_IS_CONFIG(r->rec_type)) {
00229           RecRegisterConfig(r->rec_type, r->name, r->data_type,
00230                             r->data_default, r->config_meta.update_type,
00231                             r->config_meta.check_type, r->config_meta.check_expr, r->config_meta.access_type);
00232         }
00233       } while (RecMessageUnmarshalNext(msg, &itr, &r) != REC_ERR_FAIL);
00234     }
00235     break;
00236 
00237   case RECG_PUSH:
00238     RecDebug(DL_Note, "[recv] RECG_PUSH [%d bytes]", sizeof(RecMessageHdr) + msg->o_end - msg->o_start);
00239     if (RecMessageUnmarshalFirst(msg, &itr, &r) != REC_ERR_FAIL) {
00240       do {
00241         RecForceInsert(r);
00242       } while (RecMessageUnmarshalNext(msg, &itr, &r) != REC_ERR_FAIL);
00243     }
00244     break;
00245 
00246   case RECG_PULL_ACK:
00247     RecDebug(DL_Note, "[recv] RECG_PULL_ACK [%d bytes]", sizeof(RecMessageHdr) + msg->o_end - msg->o_start);
00248     if (RecMessageUnmarshalFirst(msg, &itr, &r) != REC_ERR_FAIL) {
00249       do {
00250         RecForceInsert(r);
00251       } while (RecMessageUnmarshalNext(msg, &itr, &r) != REC_ERR_FAIL);
00252     }
00253     break;
00254 
00255   case RECG_PULL_REQ:
00256     RecDebug(DL_Note, "[recv] RECG_PULL_REQ [%d bytes]", sizeof(RecMessageHdr) + msg->o_end - msg->o_start);
00257     send_pull_message(RECG_PULL_ACK);
00258     break;
00259 
00260   default:
00261     ink_assert(!"Unexpected RecG type");
00262     return REC_ERR_FAIL;
00263 
00264   }
00265 
00266   return REC_ERR_OKAY;
00267 }
00268 
00269 
00270 
00271 
00272 
00273 #define REC_REGISTER_STAT_XXX(A, B) \
00274   ink_assert((rec_type == RECT_NODE)    || \
00275                    (rec_type == RECT_CLUSTER) || \
00276                    (rec_type == RECT_PROCESS) || \
00277                    (rec_type == RECT_LOCAL)   || \
00278                    (rec_type == RECT_PLUGIN));   \
00279   RecRecord *r; \
00280   RecData my_data_default; \
00281   my_data_default.A = data_default; \
00282   if ((r = RecRegisterStat(rec_type, name, B, my_data_default, \
00283                            persist_type)) != NULL) { \
00284     if (i_am_the_record_owner(r->rec_type)) { \
00285       r->sync_required = r->sync_required | REC_PEER_SYNC_REQUIRED; \
00286     } else { \
00287       send_register_message(r); \
00288     } \
00289     return REC_ERR_OKAY; \
00290   } else { \
00291     return REC_ERR_FAIL; \
00292   }
00293 
00294 int
00295 _RecRegisterStatInt(RecT rec_type, const char *name, RecInt data_default, RecPersistT persist_type)
00296 {
00297   REC_REGISTER_STAT_XXX(rec_int, RECD_INT);
00298 }
00299 
00300 int
00301 _RecRegisterStatFloat(RecT rec_type, const char *name, RecFloat data_default, RecPersistT persist_type)
00302 {
00303   REC_REGISTER_STAT_XXX(rec_float, RECD_FLOAT);
00304 }
00305 
00306 int
00307 _RecRegisterStatString(RecT rec_type, const char *name, RecString data_default, RecPersistT persist_type)
00308 {
00309   REC_REGISTER_STAT_XXX(rec_string, RECD_STRING);
00310 }
00311 
00312 int
00313 _RecRegisterStatCounter(RecT rec_type, const char *name, RecCounter data_default, RecPersistT persist_type)
00314 {
00315   REC_REGISTER_STAT_XXX(rec_counter, RECD_COUNTER);
00316 }
00317 
00318 
00319 
00320 
00321 
00322 #define REC_REGISTER_CONFIG_XXX(A, B) \
00323   RecRecord *r; \
00324   RecData my_data_default; \
00325   my_data_default.A = data_default; \
00326   if ((r = RecRegisterConfig(rec_type, name, B, my_data_default, \
00327                              update_type, check_type,              \
00328                              check_regex, access_type)) != NULL) { \
00329     if (i_am_the_record_owner(r->rec_type)) { \
00330       r->sync_required = r->sync_required | REC_PEER_SYNC_REQUIRED; \
00331     } else { \
00332       send_register_message(r); \
00333     } \
00334     return REC_ERR_OKAY; \
00335   } else { \
00336     return REC_ERR_FAIL; \
00337   }
00338 
00339 int
00340 RecRegisterConfigInt(RecT rec_type, const char *name,
00341                      RecInt data_default, RecUpdateT update_type,
00342                      RecCheckT check_type, const char *check_regex, RecAccessT access_type)
00343 {
00344   ink_assert((rec_type == RECT_CONFIG) || (rec_type == RECT_LOCAL));
00345   REC_REGISTER_CONFIG_XXX(rec_int, RECD_INT);
00346 }
00347 
00348 int
00349 RecRegisterConfigFloat(RecT rec_type, const char *name,
00350                        RecFloat data_default, RecUpdateT update_type,
00351                        RecCheckT check_type, const char *check_regex, RecAccessT access_type)
00352 {
00353   ink_assert((rec_type == RECT_CONFIG) || (rec_type == RECT_LOCAL));
00354   REC_REGISTER_CONFIG_XXX(rec_float, RECD_FLOAT);
00355 }
00356 
00357 
00358 int
00359 RecRegisterConfigString(RecT rec_type, const char *name,
00360                         const char *data_default_tmp, RecUpdateT update_type,
00361                         RecCheckT check_type, const char *check_regex, RecAccessT access_type)
00362 {
00363   RecString data_default = (RecString)data_default_tmp;
00364   ink_assert((rec_type == RECT_CONFIG) || (rec_type == RECT_LOCAL));
00365   REC_REGISTER_CONFIG_XXX(rec_string, RECD_STRING);
00366 }
00367 
00368 int
00369 RecRegisterConfigCounter(RecT rec_type, const char *name,
00370                          RecCounter data_default, RecUpdateT update_type,
00371                          RecCheckT check_type, const char *check_regex, RecAccessT access_type)
00372 {
00373   ink_assert((rec_type == RECT_CONFIG) || (rec_type == RECT_LOCAL));
00374   REC_REGISTER_CONFIG_XXX(rec_counter, RECD_COUNTER);
00375 }
00376 
00377 
00378 
00379 
00380 
00381 int
00382 RecSetRecord(RecT rec_type, const char *name, RecDataT data_type, RecData *data, RecRawStat *data_raw, bool lock, bool inc_version)
00383 {
00384   int err = REC_ERR_OKAY;
00385   RecRecord *r1;
00386 
00387   
00388   
00389   if (lock) {
00390     ink_rwlock_wrlock(&g_records_rwlock);
00391   }
00392 
00393   if (ink_hash_table_lookup(g_records_ht, name, (void **) &r1)) {
00394     if (i_am_the_record_owner(r1->rec_type)) {
00395       rec_mutex_acquire(&(r1->lock));
00396       if ((data_type != RECD_NULL) && (r1->data_type != data_type)) {
00397         err = REC_ERR_FAIL;
00398       } else {
00399         if (data_type == RECD_NULL) {
00400           ink_assert(data->rec_string);
00401           switch (r1->data_type) {
00402           case RECD_INT:
00403             r1->data.rec_int = ink_atoi64(data->rec_string);
00404             data_type = RECD_INT;
00405             break;
00406           case RECD_FLOAT:
00407             r1->data.rec_float = atof(data->rec_string);
00408             data_type = RECD_FLOAT;
00409             break;
00410           case RECD_STRING:
00411             data_type = RECD_STRING;
00412             r1->data.rec_string = data->rec_string;
00413             break;
00414           case RECD_COUNTER:
00415             r1->data.rec_int = ink_atoi64(data->rec_string);
00416             data_type = RECD_COUNTER;
00417             break;
00418           default:
00419             err = REC_ERR_FAIL;
00420             break;
00421           }
00422         }
00423 
00424         if (RecDataSet(data_type, &(r1->data), data)) {
00425           r1->sync_required = REC_SYNC_REQUIRED;
00426           if (inc_version) {
00427             r1->sync_required |= REC_INC_CONFIG_VERSION;
00428           }
00429           if (REC_TYPE_IS_CONFIG(r1->rec_type)) {
00430             r1->config_meta.update_required = REC_UPDATE_REQUIRED;
00431           }
00432         }
00433         if (REC_TYPE_IS_STAT(r1->rec_type) && (data_raw != NULL)) {
00434           r1->stat_meta.data_raw = *data_raw;
00435         }
00436       }
00437       rec_mutex_release(&(r1->lock));
00438     } else {
00439       
00440       
00441       RecRecord r2;
00442 
00443       RecRecordInit(&r2);
00444       r2.rec_type = rec_type;
00445       r2.name = name;
00446       r2.data_type = (data_type != RECD_NULL) ? data_type : r1->data_type;
00447       r2.data = *data;
00448       if (REC_TYPE_IS_STAT(r2.rec_type) && (data_raw != NULL)) {
00449         r2.stat_meta.data_raw = *data_raw;
00450       }
00451       err = send_set_message(&r2);
00452       RecRecordFree(&r2);
00453     }
00454   } else {
00455     
00456     
00457     
00458     
00459     
00460     if ((rec_type == RECT_NULL) || (data_type == RECD_NULL)) {
00461       err = REC_ERR_FAIL;
00462       goto Ldone;
00463     }
00464     r1 = RecAlloc(rec_type, name, data_type);
00465     RecDataSet(data_type, &(r1->data), data);
00466     if (REC_TYPE_IS_STAT(r1->rec_type) && (data_raw != NULL)) {
00467       r1->stat_meta.data_raw = *data_raw;
00468     }
00469     if (i_am_the_record_owner(r1->rec_type)) {
00470       r1->sync_required = r1->sync_required | REC_PEER_SYNC_REQUIRED;
00471     } else {
00472       err = send_set_message(r1);
00473     }
00474     ink_hash_table_insert(g_records_ht, name, (void *) r1);
00475 
00476   }
00477 
00478 Ldone:
00479   if (lock) {
00480     ink_rwlock_unlock(&g_records_rwlock);
00481   }
00482 
00483   return err;
00484 }
00485 
00486 int
00487 RecSetRecordConvert(const char *name, const RecString rec_string, bool lock, bool inc_version)
00488 {
00489   RecData data;
00490   data.rec_string = rec_string;
00491   return RecSetRecord(RECT_NULL, name, RECD_NULL, &data, NULL, lock, inc_version);
00492 }
00493 
00494 int
00495 RecSetRecordInt(const char *name, RecInt rec_int, bool lock, bool inc_version)
00496 {
00497   RecData data;
00498   data.rec_int = rec_int;
00499   return RecSetRecord(RECT_NULL, name, RECD_INT, &data, NULL, lock, inc_version);
00500 }
00501 
00502 int
00503 RecSetRecordFloat(const char *name, RecFloat rec_float, bool lock, bool inc_version)
00504 {
00505   RecData data;
00506   data.rec_float = rec_float;
00507   return RecSetRecord(RECT_NULL, name, RECD_FLOAT, &data, NULL, lock, inc_version);
00508 }
00509 
00510 int
00511 RecSetRecordString(const char *name, const RecString rec_string, bool lock, bool inc_version)
00512 {
00513   RecData data;
00514   data.rec_string = rec_string;
00515   return RecSetRecord(RECT_NULL, name, RECD_STRING, &data, NULL, lock, inc_version);
00516 }
00517 
00518 int
00519 RecSetRecordCounter(const char *name, RecCounter rec_counter, bool lock, bool inc_version)
00520 {
00521   RecData data;
00522   data.rec_counter = rec_counter;
00523   return RecSetRecord(RECT_NULL, name, RECD_COUNTER, &data, NULL, lock, inc_version);
00524 }
00525 
00526 
00527 
00528 
00529 
00530 int
00531 RecReadStatsFile()
00532 {
00533   RecRecord *r;
00534   RecMessage *m;
00535   RecMessageItr itr;
00536   RecPersistT persist_type = RECP_NULL;
00537   ats_scoped_str snap_fpath(RecConfigReadPersistentStatsPath());
00538 
00539   
00540   ink_rwlock_wrlock(&g_records_rwlock);
00541 
00542   if ((m = RecMessageReadFromDisk(snap_fpath)) != NULL) {
00543     if (RecMessageUnmarshalFirst(m, &itr, &r) != REC_ERR_FAIL) {
00544       do {
00545         if ((r->name == NULL) || (!strlen(r->name))) {
00546           continue;
00547         }
00548 
00549         
00550         
00551         if (RecGetRecordPersistenceType(r->name, &persist_type, false ) != REC_ERR_OKAY) {
00552           RecDebug(DL_Debug, "restoring value for persisted stat '%s'", r->name);
00553           RecSetRecord(r->rec_type, r->name, r->data_type, &(r->data), &(r->stat_meta.data_raw), false);
00554           continue;
00555         }
00556 
00557         if (!REC_TYPE_IS_STAT(r->rec_type)) {
00558           
00559           RecLog(DL_Warning, "skipping restore of non-stat record '%s'", r->name);
00560           continue;
00561         }
00562 
00563         
00564         
00565         
00566         if (persist_type == RECP_NON_PERSISTENT) {
00567           RecDebug(DL_Debug, "preserving current value of formerly persistent stat '%s'", r->name);
00568           continue;
00569         }
00570 
00571         RecDebug(DL_Debug, "restoring value for persisted stat '%s'", r->name);
00572         RecSetRecord(r->rec_type, r->name, r->data_type, &(r->data), &(r->stat_meta.data_raw), false);
00573       } while (RecMessageUnmarshalNext(m, &itr, &r) != REC_ERR_FAIL);
00574     }
00575   }
00576 
00577   ink_rwlock_unlock(&g_records_rwlock);
00578   ats_free(m);
00579 
00580   return REC_ERR_OKAY;
00581 }
00582 
00583 
00584 
00585 
00586 
00587 int
00588 RecSyncStatsFile()
00589 {
00590   RecRecord *r;
00591   RecMessage *m;
00592   int i, num_records;
00593   bool sync_to_disk;
00594   ats_scoped_str snap_fpath(RecConfigReadPersistentStatsPath());
00595 
00596   
00597 
00598 
00599 
00600   ink_assert(g_mode_type != RECM_NULL);
00601 
00602   if (g_mode_type == RECM_SERVER || g_mode_type == RECM_STAND_ALONE) {
00603     m = RecMessageAlloc(RECG_NULL);
00604     num_records = g_num_records;
00605     sync_to_disk = false;
00606     for (i = 0; i < num_records; i++) {
00607       r = &(g_records[i]);
00608       rec_mutex_acquire(&(r->lock));
00609       if (REC_TYPE_IS_STAT(r->rec_type)) {
00610         if (r->stat_meta.persist_type == RECP_PERSISTENT) {
00611           m = RecMessageMarshal_Realloc(m, r);
00612           sync_to_disk = true;
00613         }
00614       }
00615       rec_mutex_release(&(r->lock));
00616     }
00617     if (sync_to_disk) {
00618       RecDebug(DL_Note, "Writing '%s' [%d bytes]", (const char *)snap_fpath, m->o_write - m->o_start + sizeof(RecMessageHdr));
00619       RecMessageWriteToDisk(m, snap_fpath);
00620     }
00621     RecMessageFree(m);
00622   }
00623 
00624   return REC_ERR_OKAY;
00625 }
00626 
00627 
00628 static void
00629 RecConsumeConfigEntry(RecT rec_type, RecDataT data_type, const char * name, const char * value, bool inc_version)
00630 {
00631     RecData data;
00632 
00633     memset(&data, 0, sizeof(RecData));
00634     RecDataSetFromString(data_type, &data, value);
00635     RecSetRecord(rec_type, name, data_type, &data, NULL, false, inc_version);
00636     RecDataClear(data_type, &data);
00637 }
00638 
00639 
00640 
00641 
00642 int
00643 RecReadConfigFile(bool inc_version)
00644 {
00645   RecDebug(DL_Note, "Reading '%s'", g_rec_config_fpath);
00646 
00647   
00648   ink_rwlock_wrlock(&g_records_rwlock);
00649 
00650   
00651   RecConfigFileParse(g_rec_config_fpath, RecConsumeConfigEntry, inc_version);
00652 
00653   
00654   ink_rwlock_unlock(&g_records_rwlock);
00655 
00656   return REC_ERR_OKAY;
00657 }
00658 
00659 
00660 
00661 
00662 
00663 int
00664 RecSyncConfigToTB(textBuffer * tb, bool *inc_version)
00665 {
00666   int err = REC_ERR_FAIL;
00667 
00668   if (inc_version != NULL) {
00669     *inc_version = false;
00670   }
00671   
00672 
00673 
00674 
00675   ink_assert(g_mode_type != RECM_NULL);
00676 
00677   if (g_mode_type == RECM_SERVER || g_mode_type == RECM_STAND_ALONE) {
00678     RecRecord *r;
00679     int i, num_records;
00680     RecConfigFileEntry *cfe;
00681     bool sync_to_disk;
00682 
00683     ink_mutex_acquire(&g_rec_config_lock);
00684 
00685     num_records = g_num_records;
00686     sync_to_disk = false;
00687     for (i = 0; i < num_records; i++) {
00688       r = &(g_records[i]);
00689       rec_mutex_acquire(&(r->lock));
00690       if (REC_TYPE_IS_CONFIG(r->rec_type)) {
00691         if (r->sync_required & REC_DISK_SYNC_REQUIRED) {
00692           if (!ink_hash_table_isbound(g_rec_config_contents_ht, r->name)) {
00693             cfe = (RecConfigFileEntry *)ats_malloc(sizeof(RecConfigFileEntry));
00694             cfe->entry_type = RECE_RECORD;
00695             cfe->entry = ats_strdup(r->name);
00696             enqueue(g_rec_config_contents_llq, (void *) cfe);
00697             ink_hash_table_insert(g_rec_config_contents_ht, r->name, NULL);
00698           }
00699           r->sync_required = r->sync_required & ~REC_DISK_SYNC_REQUIRED;
00700           sync_to_disk = true;
00701           if (r->sync_required & REC_INC_CONFIG_VERSION) {
00702             r->sync_required = r->sync_required & ~REC_INC_CONFIG_VERSION;
00703             if (r->rec_type != RECT_LOCAL && inc_version != NULL) {
00704               *inc_version = true;
00705             }
00706           }
00707         }
00708       }
00709       rec_mutex_release(&(r->lock));
00710     }
00711 
00712     if (sync_to_disk) {
00713       char b[1024];
00714 
00715       
00716       err = REC_ERR_OKAY;
00717       tb->reUse();
00718 
00719       ink_rwlock_rdlock(&g_records_rwlock);
00720 
00721       LLQrec *llq_rec = g_rec_config_contents_llq->head;
00722       while (llq_rec != NULL) {
00723         cfe = (RecConfigFileEntry *) llq_rec->data;
00724         if (cfe->entry_type == RECE_COMMENT) {
00725           tb->copyFrom(cfe->entry, strlen(cfe->entry));
00726           tb->copyFrom("\n", 1);
00727         } else {
00728           if (ink_hash_table_lookup(g_records_ht, cfe->entry, (void **) &r)) {
00729             rec_mutex_acquire(&(r->lock));
00730             
00731             switch (r->rec_type) {
00732             case RECT_CONFIG:
00733               tb->copyFrom("CONFIG ", 7);
00734               break;
00735             case RECT_PROCESS:
00736               tb->copyFrom("PROCESS ", 8);
00737               break;
00738             case RECT_NODE:
00739               tb->copyFrom("NODE ", 5);
00740               break;
00741             case RECT_CLUSTER:
00742               tb->copyFrom("CLUSTER ", 8);
00743               break;
00744             case RECT_LOCAL:
00745               tb->copyFrom("LOCAL ", 6);
00746               break;
00747             default:
00748               ink_assert(!"Unexpected RecT type");
00749               break;
00750             }
00751             
00752             tb->copyFrom(cfe->entry, strlen(cfe->entry));
00753             tb->copyFrom(" ", 1);
00754             
00755             switch (r->data_type) {
00756             case RECD_INT:
00757               tb->copyFrom("INT ", 4);
00758               snprintf(b, 1023, "%" PRId64 "", r->data.rec_int);
00759               tb->copyFrom(b, strlen(b));
00760               break;
00761             case RECD_FLOAT:
00762               tb->copyFrom("FLOAT ", 6);
00763               snprintf(b, 1023, "%f", r->data.rec_float);
00764               tb->copyFrom(b, strlen(b));
00765               break;
00766             case RECD_STRING:
00767               tb->copyFrom("STRING ", 7);
00768               if (r->data.rec_string) {
00769                 tb->copyFrom(r->data.rec_string, strlen(r->data.rec_string));
00770               } else {
00771                 tb->copyFrom("NULL", strlen("NULL"));
00772               }
00773               break;
00774             case RECD_COUNTER:
00775               tb->copyFrom("COUNTER ", 8);
00776               snprintf(b, 1023, "%" PRId64 "", r->data.rec_counter);
00777               tb->copyFrom(b, strlen(b));
00778               break;
00779             default:
00780               ink_assert(!"Unexpected RecD type");
00781               break;
00782             }
00783             tb->copyFrom("\n", 1);
00784             rec_mutex_release(&(r->lock));
00785           }
00786         }
00787         llq_rec = llq_rec->next;
00788       }
00789       ink_rwlock_unlock(&g_records_rwlock);
00790     }
00791     ink_mutex_release(&g_rec_config_lock);
00792   }
00793 
00794   return err;
00795 }
00796 
00797 
00798 
00799 
00800 
00801 int
00802 RecExecConfigUpdateCbs(unsigned int update_required_type)
00803 {
00804   RecRecord *r;
00805   int i, num_records;
00806 
00807   num_records = g_num_records;
00808   for (i = 0; i < num_records; i++) {
00809     r = &(g_records[i]);
00810     rec_mutex_acquire(&(r->lock));
00811     if (REC_TYPE_IS_CONFIG(r->rec_type)) {
00812       
00813 
00814 
00815 
00816 
00817 
00818 
00819 
00820 
00821 
00822       if ((r->config_meta.update_required & update_required_type) && (r->config_meta.update_cb_list)) {
00823         RecConfigUpdateCbList *cur_callback = NULL;
00824         for (cur_callback = r->config_meta.update_cb_list; cur_callback; cur_callback = cur_callback->next) {
00825           (*(cur_callback->update_cb)) (r->name, r->data_type, r->data, cur_callback->update_cookie);
00826         }
00827         r->config_meta.update_required = r->config_meta.update_required & ~update_required_type;
00828       }
00829     }
00830     rec_mutex_release(&(r->lock));
00831   }
00832 
00833   return REC_ERR_OKAY;
00834 }
00835 
00836 
00837 
00838 
00839 
00840 int
00841 RecResetStatRecord(const char *name)
00842 {
00843   RecRecord *r1 = NULL;
00844   int err = REC_ERR_OKAY;
00845 
00846   if (ink_hash_table_lookup(g_records_ht, name, (void **) &r1)) {
00847     if (i_am_the_record_owner(r1->rec_type)) {
00848       rec_mutex_acquire(&(r1->lock));
00849       ++(r1->version);
00850       RecDataSet(r1->data_type, &(r1->data), &(r1->data_default));
00851       rec_mutex_release(&(r1->lock));
00852       err = REC_ERR_OKAY;
00853     } else {
00854       RecRecord r2;
00855 
00856       RecRecordInit(&r2);
00857       r2.rec_type = r1->rec_type;
00858       r2.name = r1->name;
00859       r2.data_type = r1->data_type;
00860       r2.data = r1->data_default;
00861 
00862       err = send_reset_message(&r2);
00863       RecRecordFree(&r2);
00864     }
00865   } else {
00866     err = REC_ERR_FAIL;
00867   }
00868 
00869   return err;
00870 }
00871 
00872 
00873 
00874 
00875 
00876 int
00877 RecResetStatRecord(RecT type, bool all)
00878 {
00879   int i, num_records;
00880   int err = REC_ERR_OKAY;
00881 
00882   RecDebug(DL_Note, "Reset Statistics Records");
00883 
00884   num_records = g_num_records;
00885   for (i = 0; i < num_records; i++) {
00886     RecRecord *r1 = &(g_records[i]);
00887 
00888     if (REC_TYPE_IS_STAT(r1->rec_type) && ((type == RECT_NULL) || (r1->rec_type == type)) &&
00889         (all || (r1->stat_meta.persist_type != RECP_NON_PERSISTENT)) &&
00890         (r1->data_type != RECD_STRING)) {
00891       if (i_am_the_record_owner(r1->rec_type)) {
00892         rec_mutex_acquire(&(r1->lock));
00893         ++(r1->version);
00894         if (!RecDataSet(r1->data_type, &(r1->data), &(r1->data_default))) {
00895           err = REC_ERR_FAIL;
00896         }
00897         rec_mutex_release(&(r1->lock));
00898       } else {
00899         RecRecord r2;
00900 
00901         RecRecordInit(&r2);
00902         r2.rec_type = r1->rec_type;
00903         r2.name = r1->name;
00904         r2.data_type = r1->data_type;
00905         r2.data = r1->data_default;
00906 
00907         err = send_reset_message(&r2);
00908         RecRecordFree(&r2);
00909       }
00910     }
00911   }
00912   return err;
00913 }
00914 
00915 
00916 int
00917 RecSetSyncRequired(char *name, bool lock)
00918 {
00919   int err = REC_ERR_FAIL;
00920   RecRecord *r1;
00921 
00922   
00923   
00924   if (lock) {
00925     ink_rwlock_wrlock(&g_records_rwlock);
00926   }
00927 
00928   if (ink_hash_table_lookup(g_records_ht, name, (void **) &r1)) {
00929     if (i_am_the_record_owner(r1->rec_type)) {
00930       rec_mutex_acquire(&(r1->lock));
00931       r1->sync_required = REC_SYNC_REQUIRED;
00932       if (REC_TYPE_IS_CONFIG(r1->rec_type)) {
00933         r1->config_meta.update_required = REC_UPDATE_REQUIRED;
00934       }
00935       rec_mutex_release(&(r1->lock));
00936       err = REC_ERR_OKAY;
00937     } else {
00938       
00939       
00940       
00941       
00942 
00943       
00944 
00945 
00946 
00947 
00948 
00949 
00950 
00951 
00952 
00953 
00954 
00955     }
00956   }
00957 
00958   if (lock) {
00959     ink_rwlock_unlock(&g_records_rwlock);
00960   }
00961 
00962   return err;
00963 }
00964 
00965 int RecWriteConfigFile(textBuffer *tb)
00966 {
00967 #define TMP_FILENAME_EXT_STR ".tmp"
00968 #define TMP_FILENAME_EXT_LEN (sizeof(TMP_FILENAME_EXT_STR) - 1)
00969 
00970   int nbytes;
00971   int filename_len;
00972   int tmp_filename_len;
00973   int result;
00974   char buff[1024];
00975   char *tmp_filename;
00976 
00977   filename_len = strlen(g_rec_config_fpath);
00978   tmp_filename_len = filename_len + TMP_FILENAME_EXT_LEN;
00979   if (tmp_filename_len < (int)sizeof(buff)) {
00980     tmp_filename = buff;
00981   } else {
00982     tmp_filename = (char *)ats_malloc(tmp_filename_len + 1);
00983   }
00984   sprintf(tmp_filename, "%s%s", g_rec_config_fpath, TMP_FILENAME_EXT_STR);
00985 
00986   RecDebug(DL_Note, "Writing '%s'", g_rec_config_fpath);
00987 
00988   RecHandle h_file = RecFileOpenW(tmp_filename);
00989   do {
00990     if (h_file == REC_HANDLE_INVALID) {
00991       RecLog(DL_Warning, "open file: %s to write fail, errno: %d, error info: %s",
00992           tmp_filename, errno, strerror(errno));
00993       result = REC_ERR_FAIL;
00994       break;
00995     }
00996 
00997     if (RecFileWrite(h_file, tb->bufPtr(), tb->spaceUsed(), &nbytes) != REC_ERR_OKAY) {
00998       RecLog(DL_Warning, "write to file: %s fail, errno: %d, error info: %s",
00999           tmp_filename, errno, strerror(errno));
01000       result = REC_ERR_FAIL;
01001       break;
01002     }
01003 
01004     if (nbytes != tb->spaceUsed()) {
01005       RecLog(DL_Warning, "write to file: %s fail, disk maybe full", tmp_filename);
01006       result = REC_ERR_FAIL;
01007       break;
01008     }
01009 
01010     if (RecFileSync(h_file) != REC_ERR_OKAY) {
01011       RecLog(DL_Warning, "fsync file: %s fail, errno: %d, error info: %s",
01012           tmp_filename, errno, strerror(errno));
01013       result = REC_ERR_FAIL;
01014       break;
01015     }
01016     if (RecFileClose(h_file) != REC_ERR_OKAY) {
01017       RecLog(DL_Warning, "close file: %s fail, errno: %d, error info: %s",
01018           tmp_filename, errno, strerror(errno));
01019       result = REC_ERR_FAIL;
01020       break;
01021     }
01022     h_file = REC_HANDLE_INVALID;
01023 
01024     if (rename(tmp_filename, g_rec_config_fpath) != 0) {
01025       RecLog(DL_Warning, "rename file %s to %s fail, errno: %d, error info: %s",
01026           tmp_filename, g_rec_config_fpath, errno, strerror(errno));
01027       result = REC_ERR_FAIL;
01028       break;
01029     }
01030 
01031     result = REC_ERR_OKAY;
01032   } while (0);
01033 
01034   if (h_file != REC_HANDLE_INVALID) {
01035     RecFileClose(h_file);
01036   }
01037   if (tmp_filename != buff) {
01038     ats_free(tmp_filename);
01039   }
01040   return result;
01041 }
01042