Ejemplo n.º 1
0
/* ****************************************************************************
*
* SubscriptionCache::semTake - 
*/
void SubscriptionCache::semTake(void)
{
  if (pthread_self() == mutexOwner)
  {
    return;
  }

  struct timespec  startTime;
  struct timespec  endTime;
  struct timespec  diffTime;

  if (semTimeStatistics)
  {
    clock_gettime(CLOCK_REALTIME, &startTime);
  }

  sem_wait(&mutex);
  mutexOwner = pthread_self();

  if (semTimeStatistics)
  {
    clock_gettime(CLOCK_REALTIME, &endTime);
    clock_difftime(&endTime, &startTime, &diffTime);
    clock_addtime(&subCacheMutexTime, &diffTime);
  }
}
Ejemplo n.º 2
0
/* ****************************************************************************
*
* timeStatSemTake -
*/
int timeStatSemTake(const char* who, const char* what)
{
  int r;

  LM_T(LmtTimeStatSem, ("%s taking the 'timeStat' semaphore for '%s'", who, what));

  struct timespec startTime;
  struct timespec endTime;
  struct timespec diffTime;

  if (semWaitStatistics)
  {
    clock_gettime(CLOCK_REALTIME, &startTime);
  }

  r = sem_wait(&timeStatSem);

  if (semWaitStatistics)
  {
    clock_gettime(CLOCK_REALTIME, &endTime);

    clock_difftime(&endTime, &startTime, &diffTime);
    clock_addtime(&accTimeStatSemTime, &diffTime);
  }

  LM_T(LmtTimeStatSem, ("%s has the 'timeStat' semaphore", who));

  return r;
}
Ejemplo n.º 3
0
Archivo: common.c Proyecto: baruch/nut
/* A non-monotonic clock safe difference, if the time moved backwards consider the difference as infinite. */
double clock_difftime_safe(struct timespec *after, struct timespec *before)
{
	double diff = clock_difftime(after, before);
	if (diff >= 0.0)
		return diff;
	return DBL_MAX;
}
Ejemplo n.º 4
0
/* ****************************************************************************
*
* reqSemTake -
*/
int reqSemTake(const char* who, const char* what, SemOpType reqType, bool* taken)
{
  int r;

  if (reqPolicy == SemNoneOp)
  {
    *taken = false;
    return -1;
  }

  if ((reqPolicy == SemWriteOp) && (reqType == SemReadOp))
  {
    *taken = false;
    return -1;
  }

  if ((reqPolicy == SemReadOp) && (reqType == SemWriteOp))
  {
    *taken = false;
    return -1;
  }

  LM_T(LmtReqSem, ("%s taking the 'req' semaphore for '%s'", who, what));

  struct timespec startTime;
  struct timespec endTime;
  struct timespec diffTime;

  if (semWaitStatistics)
  {
    clock_gettime(CLOCK_REALTIME, &startTime);
  }

  r = sem_wait(&reqSem);

  if (semWaitStatistics)
  {
    clock_gettime(CLOCK_REALTIME, &endTime);

    clock_difftime(&endTime, &startTime, &diffTime);
    clock_addtime(&accReqSemTime, &diffTime);
  }

  LM_T(LmtReqSem, ("%s has the 'req' semaphore", who));

  *taken = true;
  return r;
}
/* ****************************************************************************
*
* mongoPoolConnectionGet - 
*
* There are two semaphores to get a connection.
* - One binary semaphore that protects the connection-vector itself (connectionPoolSem)
* - One counting semaphore that makes the caller wait until there is at least one free connection (connectionSem)
*
* There is a limited number of connections and the first thing to do is to wait for a connection
* to become avilable (any of the N connections in the pool) - this is done waiting on the counting semaphore that is 
* initialized with "POOL SIZE" - meaning the semaphore can be taken N times if the pool size is N.
* 
* Once a connection is free, 'sem_wait(&connectionSem)' returns and we now have to take the semaphore 
* that protects for pool itself (we *are* going to modify the vector of the pool - can only do it in
* one thread at a time ...)
*
* After taking a connection, the semaphore 'connectionPoolSem' is freed, as all modifications to the connection pool
* have finished.
* The other semaphore however, 'connectionSem', is kept and it is not freed until we finish using the connection.
*
* The function mongoPoolConnectionRelease releases the counting semaphore 'connectionSem'.
* Very important to call the function 'mongoPoolConnectionRelease' after finishing using the connection !
*
*/
DBClientBase* mongoPoolConnectionGet(void)
{
  DBClientBase*    connection = NULL;
  struct timespec  startTime;
  struct timespec  endTime;
  struct timespec  diffTime;

  if (semStatistics)
  {
    clock_gettime(CLOCK_REALTIME, &startTime);
  }

  sem_wait(&connectionSem);
  sem_wait(&connectionPoolSem);

  if (semStatistics)
  {
    clock_gettime(CLOCK_REALTIME, &endTime);

    clock_difftime(&endTime, &startTime, &diffTime);
    clock_addtime(&semWaitingTime, &diffTime);
  }

  for (int ix = 0; ix < connectionPoolSize; ++ix)
  {
    if (connectionPool[ix].free == true)
    {
      connectionPool[ix].free = false;
      connection = connectionPool[ix].connection;
      break;
    }
  }

  sem_post(&connectionPoolSem);

  return connection;
}
/* ****************************************************************************
*
* jsonRequestTreat - 
*/
std::string jsonRequestTreat
(
  ConnectionInfo*            ciP,
  ParseData*                 parseDataP,
  RequestType                requestType,
  JsonDelayedRelease*        releaseP,
  std::vector<std::string>&  compV
)
{
  std::string      answer;
  struct timespec  start;
  struct timespec  end;

  if (timingStatistics)
  {
    clock_gettime(CLOCK_REALTIME, &start);
  }

  switch (requestType)
  {
  case EntitiesRequest:  // POST /v2/entities
    releaseP->entity = &parseDataP->ent.res;
    answer = parseEntity(ciP, &parseDataP->ent.res, false);
    if (answer != "OK")
    {
      return answer;
    }

    if ((answer = parseDataP->ent.res.check(ciP, EntitiesRequest)) != "OK")
    {
      OrionError error(SccBadRequest, answer);
      return error.render(ciP, "");
    }
    break;

  case EntityRequest:  // POST|PUT /v2/entities/<eid>
    releaseP->entity = &parseDataP->ent.res;
    answer = parseEntity(ciP, &parseDataP->ent.res, true);
    if (answer != "OK")
    {
      return answer;
    }

    if ((answer = parseDataP->ent.res.check(ciP, EntityRequest)) != "OK")
    {
      OrionError error(SccBadRequest, answer);
      return error.render(ciP, "");
    }
    break;

  case EntityAttributeRequest:
    releaseP->attribute = &parseDataP->attr.attribute;
    releaseP->attribute->name = compV[4];
    answer = parseContextAttribute(ciP, &parseDataP->attr.attribute);
    if (answer != "OK")
    {
      return answer;
    }

    if ((answer = parseDataP->attr.attribute.check(ciP, EntityAttributeRequest, "", "", 0)) != "OK")
    {
      OrionError error(SccBadRequest, answer);
      return error.render(ciP, "");
    }
    break;

  case EntityAttributeValueRequest:
    releaseP->attribute = &parseDataP->av.attribute;
    answer = parseAttributeValue(ciP, &parseDataP->av.attribute);
    if (answer != "OK")
    {
      return answer;
    }
    break;

  case SubscriptionsRequest:
    answer = parseSubscription(ciP, &parseDataP->subsV2);
    if (answer != "OK")
    {
      return answer;
    }
    break;

  case IndividualSubscriptionRequest:
    answer = parseSubscription(ciP, &parseDataP->subsV2, true);  // NOTE: partial == true
    if (answer != "OK")
    {
      return answer;
    }
    break;

  case BatchQueryRequest:
    answer = parseBatchQuery(ciP, &parseDataP->bq.res);
    if (answer != "OK")
    {
      return answer;
    }
    break;

  case BatchUpdateRequest:
    answer = parseBatchUpdate(ciP, &parseDataP->bu.res);
    if (answer != "OK")
    {
      return answer;
    }

    break;

  default:
    OrionError error(SccNotImplemented, "Request Treat function not implemented");
    answer = error.render(ciP, "");
    ciP->httpStatusCode = SccNotImplemented;
    break;
  }
  
  if (timingStatistics)
  {
    clock_gettime(CLOCK_REALTIME, &end);
    clock_difftime(&end, &start, &threadLastTimeStat.jsonV2ParseTime);
  }

  return answer;
}
Ejemplo n.º 7
0
/* ****************************************************************************
*
* requestCompleted -
*/
static void requestCompleted
(
  void*                       cls,
  MHD_Connection*             connection,
  void**                      con_cls,
  MHD_RequestTerminationCode  toe
)
{
  ConnectionInfo*  ciP      = (ConnectionInfo*) *con_cls;
  struct timespec  reqEndTime;

  if ((ciP->payload != NULL) && (ciP->payload != static_buffer))
  {
    free(ciP->payload);
  }

  *con_cls = NULL;

  lmTransactionEnd();  // Incoming REST request ends

  if (timingStatistics)
  {
    clock_gettime(CLOCK_REALTIME, &reqEndTime);
    clock_difftime(&reqEndTime, &ciP->reqStartTime, &threadLastTimeStat.reqTime);
  }  

  delete(ciP);

  //
  // Statistics
  //
  // Flush this requests timing measures onto a global var to be read by "GET /statistics".
  // Also, increment the accumulated measures.
  //
  if (timingStatistics)
  {
    timeStatSemTake(__FUNCTION__, "updating statistics");

    memcpy(&lastTimeStat, &threadLastTimeStat, sizeof(lastTimeStat));

    //
    // "Fix" mongoBackendTime
    //   Substract times waiting at mongo driver operation (in mongo[Read|Write|Command]WaitTime counters) so mongoBackendTime
    //   contains at the end the time passed in our logic, i.e. a kind of "self-time" for mongoBackend
    //
    clock_subtime(&threadLastTimeStat.mongoBackendTime, &threadLastTimeStat.mongoReadWaitTime);
    clock_subtime(&threadLastTimeStat.mongoBackendTime, &threadLastTimeStat.mongoWriteWaitTime);
    clock_subtime(&threadLastTimeStat.mongoBackendTime, &threadLastTimeStat.mongoCommandWaitTime);

    clock_addtime(&accTimeStat.jsonV1ParseTime,       &threadLastTimeStat.jsonV1ParseTime);
    clock_addtime(&accTimeStat.jsonV2ParseTime,       &threadLastTimeStat.jsonV2ParseTime);
    clock_addtime(&accTimeStat.mongoBackendTime,      &threadLastTimeStat.mongoBackendTime);
    clock_addtime(&accTimeStat.mongoWriteWaitTime,    &threadLastTimeStat.mongoWriteWaitTime);
    clock_addtime(&accTimeStat.mongoReadWaitTime,     &threadLastTimeStat.mongoReadWaitTime);
    clock_addtime(&accTimeStat.mongoCommandWaitTime,  &threadLastTimeStat.mongoCommandWaitTime);
    clock_addtime(&accTimeStat.renderTime,            &threadLastTimeStat.renderTime);
    clock_addtime(&accTimeStat.reqTime,               &threadLastTimeStat.reqTime);

    timeStatSemGive(__FUNCTION__, "updating statistics");
  }
}
Ejemplo n.º 8
0
/* ****************************************************************************
*
* get_curl_context_reuse -
*/
static int get_curl_context_reuse(const std::string& key, struct curl_context* pcc)
{
  pcc->curl   = NULL;
  pcc->pmutex = NULL;

  int s = pthread_mutex_lock(&contexts_mutex);

  if (s != 0)
  {
    LM_E(("Runtime Error (pthread_mutex_lock failure)"));
    return s;
  }

  std::map<std::string, struct curl_context>::iterator it;
  it = contexts.find(key);
  if (it == contexts.end())
  {
    // not found, create it
    pcc->curl = curl_easy_init();
    if (pcc->curl != NULL)
    {
      pthread_mutex_t* pm = (pthread_mutex_t *) malloc(sizeof(*pm));

      if (pm == NULL)
      {
        pthread_mutex_unlock(&contexts_mutex);
        LM_E(("Runtime Error (malloc)"));
        return -1;
      }

      int s = pthread_mutex_init(pm, NULL);
      if (s != 0)
      {
        pthread_mutex_unlock(&contexts_mutex);
        LM_E(("Runtime Error (pthread_mutex_init)"));
        free(pm);
        return s;
      }
      pcc->pmutex   = pm;
      contexts[key] = *pcc;
    }
    else  // curl_easy returned null
    {
      pcc->pmutex = NULL;    // unnecessary but clearer
    }
  }
  else // previous context found
  {
    *pcc = it->second;
  }

  s = pthread_mutex_unlock(&contexts_mutex);
  if (s != 0)
  {
    LM_E(("Runtime Error (pthread_mutex_unlock)"));
    return s;
  }

  // lock the mutex, if everything was right
  // and cc is not {NULL, NULl}
  if (pcc->pmutex != NULL)
  {
    struct timespec  startTime;
    struct timespec  endTime;
    struct timespec  diffTime;

    if (semWaitStatistics)
    {
      clock_gettime(CLOCK_REALTIME, &startTime);
    }

    s = pthread_mutex_lock(pcc->pmutex);
    if (s != 0)
    {
      LM_E(("Runtime Error (pthread_mutex_lock)"));
      return s;
    }

    if (semWaitStatistics)
    {
      clock_gettime(CLOCK_REALTIME, &endTime);
      clock_difftime(&endTime, &startTime, &diffTime);

      int s = pthread_mutex_lock(&contexts_mutex);
      if (s != 0)
      {
        LM_E(("Runtime Error (pthread_mutex_lock)"));
        return s;
      }

      clock_addtime(&accCCMutexTime, &diffTime);
      s = pthread_mutex_unlock(&contexts_mutex);
      if (s != 0)
      {
        LM_E(("Runtime Error (pthread_mutex_unlock)"));
        return s;
      }
    }
  }

  return 0;
}
Ejemplo n.º 9
0
/* ****************************************************************************
*
* xmlTreat -
*/
std::string xmlTreat
(
  const char*      content,
  ConnectionInfo*  ciP,
  ParseData*       parseDataP,
  RequestType      request,
  std::string      payloadWord,
  XmlRequest**     reqPP,
  std::string*     errorMsgP
)
{
  xml_document<>   doc;
  char*            xmlPayload = (char*) content;
  struct timespec  start;
  struct timespec  end;


  //
  // If the payload is empty, the XML parsing library does an assert
  // and the broker dies.
  // Therefore, this check here is important, to avoid death.
  // 
  // 'OK' is returned as there is no error to send a request without payload.
  //
  if ((content == NULL) || (*content == 0))
  {
    return "OK";
  }

  try
  {
    if (timingStatistics)
    {
      clock_gettime(CLOCK_REALTIME, &start);
    }

    doc.parse<0>(xmlPayload);
  }
  catch (parse_error& e)
  {
    std::string errorReply = restErrorReplyGet(ciP, ciP->outFormat, "", "unknown", SccBadRequest, "XML Parse Error");
    LM_W(("Bad Input ('%s', '%s')", content, e.what()));

    if (errorMsgP)
    {
      *errorMsgP = std::string("XML parse error exception: ") + e.what();
    }

    return errorReply;
  }
  // in this case the try/catch block is not using a 'catch (const std::exception &e)' clause, as we are not using
  // e.what(), so it wouldn't be useful
  catch (...)
  {
    std::string errorReply = restErrorReplyGet(ciP, ciP->outFormat, "", "unknown", SccBadRequest, "XML Parse Error");
    LM_W(("Bad Input (%s)", content));

    if (errorMsgP)
    {
      *errorMsgP = std::string("XML parse generic exception");
    }

    return errorReply;
  }

  xml_node<>*   father = doc.first_node();
  XmlRequest*   reqP   = xmlRequestGet(request, ciP->method);

  ciP->parseDataP = parseDataP;

  if (father == NULL)
  {
    std::string errorReply = restErrorReplyGet(ciP, ciP->outFormat, "", "unknown", SccBadRequest, "XML Parse Error");
    LM_W(("Bad Input (XML parse error)"));
    if (errorMsgP)
    {
      *errorMsgP = std::string("XML parse error: invalid XML input");
    }

    return errorReply;
  }

  if (reqP == NULL)
  {
    std::string errorReply =
      restErrorReplyGet(
        ciP,
        ciP->outFormat,
        "",
        requestType(request),
        SccBadRequest,
        std::string("Sorry, no request treating object found for RequestType /") +
        requestType(request) + "/, method /" + ciP->method + "/");

    LM_W(("Bad Input (no request treating object found for RequestType %d (%s), method %s)",
          request,
          requestType(request),
          ciP->method.c_str()));

    LM_W(("Bad Input (no request treating object found for RequestType %d (%s), method %s)",
          request, requestType(request), ciP->method.c_str()));

    if (errorMsgP)
    {
      *errorMsgP = std::string("Unable to treat ") + requestType(request) + " requests";
    }

    return errorReply;
  }


  if (reqPP != NULL)
  {
    *reqPP = reqP;
  }

  //
  // Checking that the payload matches the URL
  //
  if (((ciP->verb == POST) || (ciP->verb == PUT)) && (payloadWord.length() != 0))
  {
    std::string  errorReply;
    char*        payloadStart = (char*) content;

    // Skip '<?xml version="1.0" encoding="UTF-8"?> ' ?
    if (strncmp(payloadStart, "<?xml", 5) == 0)
    {
      ++payloadStart;
      payloadStart = strstr(payloadStart, "<");
    }

    // Skip '<'
    if (*payloadStart == '<')
    {
       ++payloadStart;
    }

    if (strncasecmp(payloadWord.c_str(), payloadStart, payloadWord.length()) != 0)
    {
      errorReply  = restErrorReplyGet(ciP,
                                      ciP->outFormat,
                                      "",
                                      reqP->keyword,
                                      SccBadRequest,
                                      std::string("Expected /") + payloadWord +
                                        "/ payload, got /" + payloadStart + "/");

      LM_W(("Bad Input (invalid  payload: wanted: '%s', got '%s')", payloadWord.c_str(), payloadStart));

      if (errorMsgP)
      {
        *errorMsgP = std::string("Bad Input (invalid payload, expecting '") +
          payloadWord + "', got '" + payloadStart + "')";
      }

      return errorReply;
    }
  }

  if (reqP->init == NULL)  // No payload treating function
  {
    return "OK";
  }

  reqP->init(parseDataP);
  ciP->httpStatusCode = SccOk;

  xmlParse(ciP, NULL, father, "", "", reqP->parseVector, parseDataP, errorMsgP);

  if (timingStatistics)
  {
    clock_gettime(CLOCK_REALTIME, &end);
    clock_difftime(&end, &start, &threadLastTimeStat.xmlParseTime);
  }

  if (ciP->httpStatusCode != SccOk)
  {
    LM_W(("Bad Input (XML parse error)"));

    return restErrorReplyGet(ciP, ciP->outFormat, "", payloadWord, ciP->httpStatusCode, ciP->answer);
  }

  LM_T(LmtParseCheck, ("Calling check for XML parsed tree (%s)", ciP->payloadWord));
  std::string check = reqP->check(parseDataP, ciP);
  if (check != "OK")
  {
    LM_W(("Bad Input (%s: %s)", reqP->keyword.c_str(), check.c_str()));

    if (errorMsgP)
    {
      *errorMsgP = std::string("Bad Input: ") + check;
    }
  }

  if (check != "OK")
  {
    if (errorMsgP)
    {
      *errorMsgP = std::string("Bad Input: ") + check;
    }
  }

  return check;
}
Ejemplo n.º 10
0
/* ****************************************************************************
*
* QueueWorkers::start() -
*/
static void *workerFunc(void* pSyncQ)
{
  SyncQOverflow<SenderThreadParams*> *queue = (SyncQOverflow<SenderThreadParams*> *) pSyncQ;
  CURL *curl;

  // Initialize curl context
  curl = curl_easy_init();

  if (curl == NULL)
  {
    LM_E(("Runtime Error (curl_easy_init)"));
    pthread_exit(NULL);
  }

  for (;;)
  {
    SenderThreadParams* params = queue->pop();
    struct timespec     now;
    struct timespec     howlong;
    size_t              estimatedQSize;

    QueueStatistics::incOut();
    clock_gettime(CLOCK_REALTIME, &now);
    clock_difftime(&now, &params->timeStamp, &howlong);
    estimatedQSize = queue->size();
    QueueStatistics::addTimeInQWithSize(&howlong, estimatedQSize);


    strncpy(transactionId, params->transactionId, sizeof(transactionId));

    LM_T(LmtNotifier, ("worker sending to: host='%s', port=%d, verb=%s, tenant='%s', service-path: '%s', xauthToken: '%s', path='%s', content-type: %s",
                       params->ip.c_str(),
                       params->port,
                       params->verb.c_str(),
                       params->tenant.c_str(),
                       params->servicePath.c_str(),
                       params->xauthToken.c_str(),
                       params->resource.c_str(),
                       params->content_type.c_str()));

    if (simulatedNotification)
    {
      LM_T(LmtNotifier, ("simulatedNotification is 'true', skipping outgoing request"));
      __sync_fetch_and_add(&noOfSimulatedNotifications, 1);
    }
    else // we'll send the notification
    {
      std::string  out;
      int          r;

      r =  httpRequestSendWithCurl(curl,
                                   params->ip,
                                   params->port,
                                   params->protocol,
                                   params->verb,
                                   params->tenant,
                                   params->servicePath,
                                   params->xauthToken,
                                   params->resource,
                                   params->content_type,
                                   params->content,
                                   true,
                                   NOTIFICATION_WAIT_MODE,
                                   &out);

      //
      // FIXME: ok and error counter should be incremented in the other notification modes (generalizing the concept, i.e.
      // not as member of QueueStatistics:: which seems to be tied to just the threadpool notification mode)
      //
      if (r == 0)
      {
        statisticsUpdate(NotifyContextSent, params->format);
        QueueStatistics::incSentOK();
      }
      else
      {
        QueueStatistics::incSentError();
      }

    }

    // Free params memory
    delete params;

    // Reset curl for next iteration
    curl_easy_reset(curl);
  }
}