C Extension für PHP



  • Hallo

    will/muss gerade etwas in C schreiben und habe nun ein Verständnissproblem 😉
    Und ich hoffe es ist hier in "C" richtig.

    Es soll eine Extension für PHP werden, welche eine ASCII Datei öffnen und die eingelesenen Zeilen in eine MySQL DB schreiben.

    Es handelt sich dabei um eine 141Mb große Datanorm Datei (Artikelstamm Datenaustausch). Es sind ca. 1.800.000 Zeilen.

    Einlesen geht ohne speichern komplett durch. Memory geht dabei auf 1.2Gb.
    (mit fopen und fgets)
    Scheibe ich auch in die MySQL DB komme ich bei 420.000 Zeilen auch schon mal auf 1.9Gb.

    Verarbeite (UPDATE/INSERT) ich so ca. 420.000 Zeilen ist auch alles ok.
    Nur sobald ich dann so ca. 900.000 Zeilen habt bricht alles ab. Leider sehe ich keine Fehlermeldung 😞

    Nun weiss ich aber nicht wo ich noch suchen muss.

    Zum Testen lasse ich immer nur 50 Zeilen oder mal mehr laufen, dabei sieht dann alles OK aus.
    Die Funktionen _paw_dn4_satz_* verarbeiten und schreiben die jeweilige Zeile.

    Ich nutze ein normales Debian 4 32-bit mit 4Gb. Das Problem habe ich aber auch auf Debian 4 64-bit Debian 5 32/64-bit.

    Es ist bestimmt ein ganz ..... Anfänger Fehler also bitte nicht zu sehr Schimpfen 😉

    Aber schon mal Danke für Tips und Hilfen!!

    Thomas

    FILE *datei;
        datei = fopen(dateiname, "r");
        if(datei != NULL)
          php_printf("Datei erfolgreich geöffnet\n");
        else {
          php_printf("Fehler beim Öffnen der Datei");
          RETURN_FALSE;
        }
    
        int c = 0;
        int BUF = 512;
        char temp[BUF];
        char *neu;
        char *temp_cd;
        int count_a = 0, count_b = 0, count_d = 0, count_p = 0, count_r = 0, count_s = 0, count_t = 0;
        while ( fgets(temp, BUF, datei) != NULL ) {
    
          c++; 
    /*nur noch zum testen damit ich die ausgabe testen kann */
          if (c < 50 ) {  // 384000
    /*nur noch zum testen damit ich die ausgabe testen kann */
    
          temp_cd = calloc(1,strlen(temp)*1+1);
          temp_cd = _paw_convert( "850", "UTF-8", temp);
          neu = calloc(1,strlen(temp_cd)*1.5+1);
          mysql_escape_string(neu, temp_cd, strlen(temp_cd));
          temp_cd = neu;
          if ( strncmp(temp_cd, "A", 1) == 0 ) {
            if ( strncmp(satzart, "A", 1) == 0 ) {
              count_a++;
    //          _paw_dn4_satz_a(lfnummer, temp_cd);
            }
          }
          else if ( strncmp(temp_cd, "B", 1) == 0 ) {
            if ( strncmp(satzart, "B", 1) == 0 ) {
              count_b++;
    //          _paw_dn4_satz_b(lfnummer, temp_cd);
            }
          }
          else if ( strncmp(temp_cd, "D", 1) == 0 ) count_d++;
          else if ( strncmp(temp_cd, "P", 1) == 0 ) count_p++;
          else if ( strncmp(temp_cd, "R", 1) == 0 ) count_r++;
          else if ( strncmp(temp_cd, "S", 1) == 0 ) count_s++;
          else if ( strncmp(temp_cd, "T", 1) == 0 ) {
            if ( strncmp(satzart, "T", 1) == 0 ) {
              count_t++;
    //          _paw_dn4_satz_t(lfnummer, temp_cd);
            }
          }
          else php_printf("##->FEHLER :: %s<-##<br>", temp_cd );
    
          free(neu);
          neu = NULL;
          temp_cd = NULL;
    
    /*nur noch zum testen damit ich die ausgabe testen kann */
          }
    /*nur noch zum testen damit ich die ausgabe testen kann */
    
        }
    
        php_printf("ZEILEN::%i##<br>", c);
        php_printf("ANZAHL::A=%i B=%i D=%i P=%i R=%i S=%i T=%i<br>", count_a, count_b, count_d, count_p, count_r, count_s, count_t);
    


  • Speicherlecks.

    temp_cd = calloc(1,strlen(temp)*1+1);  // Hier holst du Speicher
    temp_cd = _paw_convert( "850", "UTF-8", temp);  // und hier geht er schon verloren. Du kommst nicht mehr dran.
    
    neu = calloc(1,strlen(temp_cd)*1.5+1); // Hier holst du Speicher
    mysql_escape_string(neu, temp_cd, strlen(temp_cd));  // und hier nutzt du ihn ungepüft.
    

    Statt if ( strncmp(temp_cd, "A", 1) == 0 ) nimm besser (schneller)

    if ( *temp_cd == 'A')
    


  • tomj schrieb:

    Einlesen geht ohne speichern komplett durch. Memory geht dabei auf 1.2Gb.
    (mit fopen und fgets)

    Wieso geht der Speicher hoch wenn du zeilenweise einliest?

    tomj schrieb:

    int BUF = 512;
        char temp[BUF]; /* das ist VLA Zeugs, weg damit */
     ...
          temp_cd = calloc(1,strlen(temp)*1+1);
          temp_cd = _paw_convert( "850", "UTF-8", temp); /* auch Unsinn, voriges temp_cd kann nicht mehr verarbeitet und freigegeben werden */
          neu = calloc(1,strlen(temp_cd)*1.5+1); /* das dauernde calloc/free ist ebenso suboptimal */
    

    Wenn MySQL irgendwo irgendwie abbricht, kann der Abbruch nicht am C-Modul liegen; üblicherweise geben Schnittstellenfunktionen Fehlercodes zurück, werte diese aus bzw. stelle überhaupt erst einmal fest, welcher Funktionsaufruf zum Abbruch führt.



  • Danke Dir für die schnell Antwort, aber...

    stimmt

    temp_cd = calloc(1,strlen(temp)*1+1);  // Hier holst du Speicher
    

    kann ich mir sparen

    nur

    neu = calloc(1,strlen(temp_cd)*1.5+1); // Hier holst du Speicher
    

    nicht. wie meinst Du das mit dem prüfen?

    ok

    if ( *temp_cd == 'A')
    

    bringt schon was, dacht erst nur es geht nicht, da temp_cd ja länger ist.

    Es wird aber trotzdem noch der Speicher verbraucht.



  • [quote="Wutz"]

    tomj schrieb:

    Wenn MySQL irgendwo irgendwie abbricht, kann der Abbruch nicht am C-Modul liegen; üblicherweise geben Schnittstellenfunktionen Fehlercodes zurück, werte diese aus bzw. stelle überhaupt erst einmal fest, welcher Funktionsaufruf zum Abbruch führt.

    Lasse nebenbei in eine Session 'top' mit laufen und sehe wie der Apache Prozess auf die 100% Speicher zugeht und dann ist plötzlich Ende.

    Ok dann werde ich mal beim MySQL Speichern weiter suchen.



  • tomj schrieb:

    nur

    neu = calloc(1,strlen(temp_cd)*1.5+1); // Hier holst du Speicher
    

    nicht. wie meinst Du das mit dem prüfen?

    calloc kann auch NULL zurück geben.

    tomj schrieb:

    if ( *temp_cd == 'A')
    

    bringt schon was, dacht erst nur es geht nicht, da temp_cd ja länger ist.

    Es wird aber trotzdem noch der Speicher verbraucht.

    Du prüfst doch nur das erste Zeichen.



  • Hi,

    wollte nur kurz mal schreiben wo das Problem war.

    Ich hatte in der Funktion zum Speichern den MySQL-Query mit

    spprintf(&myquery, 0, "INSERT INTO art_d_satz_b SET lieferanten_id = '%s',%s ON DUPLICATE KEY UPDATE %s;", lfnummer, query1, query1);
    

    zusammen gesetzt!!

    nun mache ich es so

    strcpy(myquery, "");
      strcat(myquery, "INSERT INTO art_d_satz_b SET lieferanten_id = '");
      strcat(myquery, lfnummer);
      strcat(myquery, "',");
      strcat(myquery, query1);
      strcat(myquery, " ON DUPLICATE KEY UPDATE ");
      strcat(myquery, query1);
      strcat(myquery, ";");
    

    sind zwar mehr Zeilen, aber die Speichernutzung durch Apache bleibt bei 3-5% und alle 1.900.000 Datensätze durchlaufen in fast 10 Minuten ein INSDERT oder UPDATE.

    noch mal Danke

    Thomas


Anmelden zum Antworten