Probleme mit dem Ticker

Hier können sich alle gegenseitig helfen beim erstellen eines Spiels

Moderator: Agatho

Probleme mit dem Ticker

Beitragvon Grummli » 10.07.2004, 21:27

Ich versuche seit einiger Zeit das Spiel unter Windows zum laufen zu kriegen. Klappt auch alles soweit, es funktioniert nach einigen Änderungen anscheinend wie es soll. Alles, bis auf den Ticker.

Ich hab die Tickersource auf Windows angepaßt, alle unix funktionen geändert oder rausgeschmissen. Der Ticker compiliert ohne Fehler. Allerdings hat er Probleme, sobald er längere Strings (> 1024) in MySQL eintragen soll. Die generierten resourcen Strings sind aber um einiges Länger (um die 8000).
Nach einem bißchen schauen in den Funktionen und etwas debugging scheint es als hängt das mit der Dynamischenspeicherzuweisung zusammen.
Wenn ich in der Funktion dstring_new einen größeren Wert als 1024 eintrage funktioniert alles wie es soll, nur dummerweise bekomme ich anscheinen dadurch ein Memoryleak. Im Taskmanager steigt der benutzte Speicher stetig an, obwohl der Ticker im Leerlauf ist. Bei einem Wert von 1024 macht er das nicht.
Es scheint als wenn die Funktion dstring_vappend nach mehrmaligen Aufrufen, wie es ja im Resourcenticker geschieht, irgendwann den vorigen String löscht und damit nur dieser eine Teilstring zu Mysql übergeben wird.

Ich kenne mich leider nicht besonders mit C aus, vielleicht kann mir hier jemand erklären wo der Fehler ist. Hat es damit zu tun dass es auf Win anstatt auf Unix läuft? Oder ist das ein Bug in der Source?
Ich kann mir nicht erklären, wo hier der Fehler sein soll. ABer naja ich bin auch kein Programmierer. Wäre dankbar für hilfe.
Grummli
Proviantschlepper
Proviantschlepper
 
Beiträge: 66
Registriert: 18.02.2004, 20:53

Beitragvon Grummli » 12.07.2004, 15:45

*bump*

Niemand ne Ahnung?
Grummli
Proviantschlepper
Proviantschlepper
 
Beiträge: 66
Registriert: 18.02.2004, 20:53

Beitragvon hasdrubal » 12.07.2004, 20:47

Ne nicht wirklich. Ein paar Vermutungen höchstens.

Es sieht für mich auch nach nem Memoryleak aus. Aber ich vermute eher, dass du beim Anpassen des Codes irgendwo das Freigeben einer Variable gelöscht hast. Ich würde in irgendeiner äußeren Schleife nach benutzten Variablen und deren Freigabe gucken. Sag dochmal wie schnell der Speicherbedarf steigt.

Ich würde dir raten dir mal ne Entwicklungsumgebung zu installieren, und das Ding mal zu Debuggen.
Eine gute, kostenlose Java und neuerdings auch C/C++ IDE ist Eclipse: http://www.eclipse.org/.
hasdrubal
Einäugiger Foren-Bettler
Einäugiger Foren-Bettler
 
Beiträge: 165
Registriert: 28.02.2004, 16:33
Wohnort: Frankfurt

Beitragvon Grummli » 13.07.2004, 00:41

Ja es ist definitiv ein Leak. Ich hab heute mal den ganzen Nachmittag damit verbracht zu testen. Leider bin ich genauso weit wie vorher.
Ich hab heute mal mit einer komplett frischen Source angefangen und dort nur die Sachen geändert, die auf Win nicht funktionieren. Z.B. usleep, kill etc. Keine normalen Variablen oder gar Schleifen geändert. Und ich mußte feststellen, dass der Effekt auch dort auftrat.
Was ich oben geschrieben habe mit der geänderten Variable ist quatsch. Ob man die ändert oder nicht, das Loch ist trotzdem da.
Wie auch immer ich hab zum test mal nach und nach die Hauptschleife in ticker.c auskommentiert, und siehe da, wenn man die sql-Abfrage rausnimmt (direkt nach dem for), leckt er nicht. Scheint irgendwie mit der mysql_query_fmt zusammenzuhängen.
Dabei mal gleich eine Frage: Diese Abfrage soll doch wohl einmal pro sek durchgefürht werden oder lieg ich da falsch?
Der Speicher zählt pro sek 12k dazu, was ein wenig viel ist.
Habs auch schon mit dem gc leaktester versucht aber ich bin offenbar zu blöd den zu installieren.
Ich werd aber mal den eclipse ausprobieren, mal sehen was bei rumkommt.
Soweit schonmal vielen Dank.


---- edit: ---
Hat sich erledigt. Hab meine eigene SQL Abfrage Routine eingebaut, nun leckt es nicht mehr und funktioniert anscheinend sogar.
Grummli
Proviantschlepper
Proviantschlepper
 
Beiträge: 66
Registriert: 18.02.2004, 20:53

Beitragvon hasdrubal » 13.07.2004, 19:49

Gratulation.
Ich hab mir die Passage auch nochmal angeguckt. Ich bin sicher es hatte etwas mit den Arrays zu tun, die bei der Mysql-Abfrage gefüllt werden. Das wären typische Kanidaten für nen Speicherfresser.
Wie hast dus denn jetzt gelöst?
Könntest du mal den Original und deinen neuen Code posten? Nur so aus Neugierde *g
hasdrubal
Einäugiger Foren-Bettler
Einäugiger Foren-Bettler
 
Beiträge: 165
Registriert: 28.02.2004, 16:33
Wohnort: Frankfurt

Beitragvon Grummli » 14.07.2004, 01:07

Ok kann ich machen. Hier das original:
Code: Alles auswählen
      for (i = 0; i < eventTableSize; ++i)
      {
   MYSQL_RES *result;

   /* get only the next non-blocked event, if its timestamp
      is smaller than the smallest found timestamp */
   debug(DEBUG_EVENTS, "query event table: %s", eventTableList[i].table);

// Diese Abfrage brachte das Loch ---------------------------------------

   result = mysql_query_fmt(database,
          "SELECT * FROM %s WHERE %s = 0 AND %s < '%s' "
          "ORDER BY %s ASC, %s ASC LIMIT 0,1",
          eventTableList[i].table,
          eventTableList[i].block_field,
          eventTableList[i].time_field, next_timestamp,
          eventTableList[i].time_field,
          eventTableList[i].id_field);

// -----------------------------------------------------------------------------

   if (mysql_num_rows(result))   /* is there an earlier event? */
   {
     /* extract this earlier event's needed data */
     MYSQL_ROW row = mysql_fetch_row(result);

     next_result = result;      /* remember the earlier one */
     next_timestamp =
       mysql_get_string_field(result, row, eventTableList[i].time_field);
     next_db_eventID =
       mysql_get_string_field(result, row, eventTableList[i].id_field);
     next_eventType = i;

     mysql_data_seek(result, 0);   /* move the row pointer back */
   }
      }

      if (strcmp(next_timestamp, make_timestamp(timestamp, time(NULL))) > 0)
      {
   debug(DEBUG_EVENTS, "no event pending, sleep");
   ++sleeps;
   usleep(sleep_time);
      }
      else
      {
   debug(DEBUG_TICKER, "event: scheduled %s, now %s",
         next_timestamp, timestamp);

   /* check which handler to call (resource ticker or event handler) */
   if (next_result)
   {
     /* found an event in the event tables: block the event */
     debug(DEBUG_EVENTS, "block event: %s", next_db_eventID);
     ++events;

     mysql_query_fmt(database, "UPDATE %s SET %s = 1 WHERE %s = %s",
           eventTableList[next_eventType].table,
           eventTableList[next_eventType].block_field,
           eventTableList[next_eventType].id_field,
           next_db_eventID);

     /* call handler and delete event */
     eventTableList[next_eventType].handler(database, next_result);

     debug(DEBUG_EVENTS, "delete event: %s", next_db_eventID);

     mysql_query_fmt(database, "DELETE FROM %s WHERE %s = %s",
           eventTableList[next_eventType].table,
           eventTableList[next_eventType].id_field,
           next_db_eventID);
   }
   else
   {
     /* next event is resource tick: call resource ticker */
     debug(DEBUG_TICKER, "resource tick %s", resource_timestamp);

     resource_ticker(database, tick_advance());
     debug(DEBUG_TICKER, "resource tick ended");
     tick_log();         /* log last successful update */
   }
      }


Und hier meiner:
Code: Alles auswählen
      for (i = 0; i < eventTableSize; ++i)
      {
   /* get only the next non-blocked event, if its timestamp
      is smaller than the smallest found timestamp */
   debug(DEBUG_EVENTS, "query event table: %s", eventTableList[i].table);

char *myquery;
myquery=malloc(1024); /*Make sure we have enough space for the query */
  /* Build query */
sprintf(myquery, "SELECT * FROM %s WHERE %s = 0 AND %s < '%s' ORDER BY %s ASC, %s ASC LIMIT 0,1",
          eventTableList[i].table,
          eventTableList[i].block_field,
          eventTableList[i].time_field, next_timestamp,
          eventTableList[i].time_field,
          eventTableList[i].id_field);

mysql_real_query(database, myquery, strlen(myquery));
result = mysql_store_result(database); /* Download result from server */

   if (mysql_num_rows(result)>0)   /* is there an earlier event? */
   {
     /* extract this earlier event's needed data */
     MYSQL_ROW row = mysql_fetch_row(result);

     next_result = result;      /* remember the earlier one */
     next_timestamp =
       mysql_get_string_field(result, row, eventTableList[i].time_field);
     next_db_eventID =
       mysql_get_string_field(result, row, eventTableList[i].id_field);
     next_eventType = i;

     mysql_data_seek(result, 0);   /* move the row pointer back */
    
if (strcmp(next_timestamp, make_timestamp(timestamp, time(NULL))) < 0)
      {    

        debug(DEBUG_TICKER, "event: scheduled %s, now %s",
         next_timestamp, timestamp);
    
     /* found an event in the event tables: block the event */
     debug(DEBUG_EVENTS, "block event: %s", next_db_eventID);
       debug(DEBUG_TICKER, "block event: %s", next_db_eventID);
     ++events;

//printf("Blocking next_db_eventID: %s\n\r", next_db_eventID);
     mysql_query_fmt(database, "UPDATE %s SET %s = 1 WHERE %s = %s",
           eventTableList[next_eventType].table,
           eventTableList[next_eventType].block_field,
           eventTableList[next_eventType].id_field,
           next_db_eventID);

     /* call handler and delete event */
     eventTableList[next_eventType].handler(database, next_result);

     debug(DEBUG_EVENTS, "delete event: %s", next_db_eventID);
//printf("Deleting next_db_eventID: %s\n\r", next_db_eventID);
     mysql_query_fmt(database, "DELETE FROM %s WHERE %s = %s",
           eventTableList[next_eventType].table,
           eventTableList[next_eventType].id_field,
           next_db_eventID);

} // end if timestamp compare

   }
free(myquery);
mysql_free_result(result); /* Release memory used to store results. */

      }

      if (strcmp(next_timestamp, make_timestamp(timestamp, time(NULL))) > 0)
      {
   debug(DEBUG_EVENTS, "no event pending, sleep");
   ++sleeps;
   sleep(sleep_time);
      }
      else
      {
     /* next event is resource tick: call resource ticker */
     debug(DEBUG_TICKER, "resource tick %s", resource_timestamp);

     resource_ticker(database, tick_advance());
     debug(DEBUG_TICKER, "resource tick ended");
     tick_log();         /* log last successful update */
      }


Aber nicht lachen. Ich hab von C keinerlei Ahnung. Naja nach den paar Tagen jetzt doch ein wenig *g*
Auf jeden Fall funktionierts nun besser, obwohl er immer noch leckt wenn diverse SQL Abfragen gemacht werden. Nur halt nicht mehr jede Sekunde. Und damit kann ich leben.
Vielleicht fällt ja jemandem noch was besseres ein.
Grummli
Proviantschlepper
Proviantschlepper
 
Beiträge: 66
Registriert: 18.02.2004, 20:53

Beitragvon Firak » 16.07.2004, 23:35

Ich war leider diese Woche über sehr beschäftigt, so daß ich erst jetzt was dazu schreiben kann.

Es würde mich schon sehr wundern, wenn bei jedem Schleifendurchlauf im Ticker (Grummli: ja, das soll einmal pro Sekunde passieren) Speicher nicht wieder freigegeben würde. Schließlich läuft der Ticker bei uns manchmal ein bis zwei Monate ununterbrochen durch, ohne daß der Prozeß dabei Speicher verschlingt. Und da macht er sicher mehr Datenbankabfragen als bei Dir... ;-)

Von daher würde ich darauf tippen, daß es entweder mit Deinen Änderungen zu tun hat, oder mit der Umgebung, in der Du das Programm übersetzt (Compiler, Bibliotheken etc.).

Könntest Du mir mal die geänderten Dateien des Tickers schicken (oder einen Diff davon)?

PS: Wenn Du mir genau sagen kannst, welche Funktionen es unter Windows gibt, die man für die nicht vorhandenen einsetzen kann, könnte ich das entsprechend in unserem Quellcode anzupassen versuchen (sofern das geht).
Night falls and the foul are abroad...
Firak
Halbgott des Schattens
Halbgott des Schattens
 
Beiträge: 169
Registriert: 28.01.2004, 14:35
Wohnort: Osnabrück

Beitragvon Grummli » 17.07.2004, 23:58

Na es hätte mich auch überrascht wenn der Bug von euch wäre und es niemand gemerkt hätte ;)
Allerdings bezweifle ich, dass es an meinen Änderungen liegt, da die nicht so weitgreifen waren. Ich hatte auch schon gedacht, dass es möglicherweise an meine MySql Library liegen könnte, aber das zu checken übersteigt nun wirklich meine Fähigkeiten.

Aber ich werd dir morgen mal die geänderten Dateien schicken.
Grummli
Proviantschlepper
Proviantschlepper
 
Beiträge: 66
Registriert: 18.02.2004, 20:53


Zurück zu Bastelstube für die CVS Version

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 0 Gäste