kogmo_timestamp_t
kogmo_timestamp_from_string (char *str)
{
  kogmo_timestamp_t ts;
  int err;
  struct tm tmx;
  time_t secs;
  char ns_string[10]="";
  char *ns_string_end;
  unsigned long int ns=0;
  int i;
  long long int lli;

  if ( str == NULL )
    return 0;
  memset ( &tmx, 0, sizeof(struct tm));
  ns = 0;
  err = sscanf ( str, "%d-%d-%d%*[ _tT]%d:%d:%d.%9s",
                 &tmx.tm_year, &tmx.tm_mon , &tmx.tm_mday,
                 &tmx.tm_hour, &tmx.tm_min, &tmx.tm_sec,
                 ns_string );
  // we need at least a date (time will be 00:00:00.0 then)
  if ( err < 3 )
    {
      // for even more comfort, this also accepts times relative to now,
      // +/- followed by an offset in secondstimestamps (e.g. +12.3 or -7.25)
      if ( str[0] == '+' || str[0] == '-' )
        {
          double off;
          err = sscanf ( str, "%lf", &off);
          if ( err != 1 )
            return 0;
          ts = kogmo_timestamp_add_secs ( kogmo_timestamp_now (), off);
          return ts;
        }
      // for your comfort, this also accepts timestamps (>9999)
      err = sscanf ( str, "%lli", &lli);
      ts = (kogmo_timestamp_t) lli;
      if ( err != 1 || ts <= 9999)
        return 0;
      return ts;
    }
  // the ranges of those value are a horrible confusion, see mktime(3)
  tmx.tm_year -= 1900;
  tmx.tm_mon -= 1;
  tmx.tm_isdst = -1;
  secs = mktime (&tmx);
  if ( secs < 0 )
    return 0;
  ns = strtoul(ns_string, &ns_string_end, 10);
  // calculate the correct decimal fraction (9 digits)
  // this is: ns *= pow ( 10, 9 - strlen (ns_string) );
  // but prevent dependency from math-library
  for(i=ns_string_end-ns_string;i<9;i++)
    ns *= 10;
  ts = (kogmo_timestamp_t)ns +
       (kogmo_timestamp_t)secs * KOGMO_TIMESTAMP_TICKSPERSECOND;
  return ts;
}
int
kogmo_rtdb_objmeta_purge_objs (kogmo_rtdb_handle_t *db_h)
{
  int i;
  kogmo_rtdb_obj_info_t *scan_objmeta_p;
  kogmo_rtdb_objid_t scan_oid;
  kogmo_timestamp_t ts,scan_delete_ts;
  int purge_keep_alloc = 0;
  int percent_free;

  CHK_DBH("kogmo_rtdb_objmeta_purge",db_h,0);

  percent_free = (float)db_h->localdata_p -> heap_free * 100 /
                 db_h->localdata_p -> heap_size;

#ifndef KOGMO_RTDB_HARDREALTIME
  if ( percent_free < KOGMO_RTDB_PURGE_KEEPALLOC_PERCFREE )
    {
      DBG("purging preallocated memory, because only %i%% (<%i%%) is free",
          percent_free, KOGMO_RTDB_PURGE_KEEPALLOC_PERCFREE);
      purge_keep_alloc = 1;
    }
#endif

  ts = kogmo_rtdb_timestamp_now(db_h);

  kogmo_rtdb_objmeta_lock(db_h);
  for(i=0;i<KOGMO_RTDB_OBJ_MAX;i++)
    {
      scan_objmeta_p = &db_h->localdata_p -> objmeta[i];
      scan_oid = scan_objmeta_p->oid;
      scan_delete_ts = scan_objmeta_p -> deleted_ts;
      if (scan_oid && scan_delete_ts)
        {
          scan_delete_ts = kogmo_timestamp_add_secs(
               scan_delete_ts,
               scan_objmeta_p -> history_interval > db_h->localdata_p->default_keep_deleted_interval ?
               scan_objmeta_p -> history_interval : db_h->localdata_p->default_keep_deleted_interval);
          if ( scan_delete_ts < ts )
            {
              if ( scan_objmeta_p->flags.keep_alloc &&
                   ( !purge_keep_alloc ||
                     kogmo_timestamp_diff_secs ( scan_delete_ts, ts ) < KOGMO_RTDB_PURGE_KEEPALLOC_MAXSECS) )
                continue; // this is kept allocated and alloc-purce time is not reached or we do not purge
              kogmo_rtdb_obj_purgeslot(db_h, i);
              kogmo_rtdb_objmeta_unlock_notify(db_h);
              // give priority inheritance protocols a point to kick in
              kogmo_rtdb_objmeta_lock(db_h);
            }
        }
    }
  kogmo_rtdb_objmeta_unlock(db_h);

  percent_free = (float)db_h->localdata_p -> heap_free * 100 /
                 db_h->localdata_p -> heap_size;
  DBG("purge: %i%% free (%lli/%lli)", percent_free,
      (long long int) db_h->localdata_p -> heap_free,
      (long long int) db_h->localdata_p -> heap_size);

  return 0;
}