Mostra notizie nelle discussioni
  • Avatar
    Scritto da
    Non Autenticato
    il 2018-04-03 13:49:47.0 alle 2018-04-03 13:49:47.0
    Mentre i due snowflake starnazzano
    Il bug è stato risolto.

    Lunga vita al forum!! Lunga vita al ré!! Ficoso

    Ci speravate, vero, che questo progetto di libertà di espressione fallisse? E invece non è così, perché quando Mattia introduce un bug è capace di ripararlo, mentre voi siete qui a starnazzare.

    Ora però voglio proprio vedere quanto sono bravi due snowflake, che fanno tanto i fighi.

    In questo thread perciò cercheremo di capire l'errore e sicuramente i due snowflake saranno in grado di spiegarlo.

    Ecco come si presentava il metodo quando dava problemi...


    public List<String> getForums() {
    
            String query = "select forums.id\n" + 
                    "from forums\n" + 
                    "left join messages on forums.id=messages.forum\n" + 
                    "and forums.enabled=1\n" + 
                    "group by forums.id\n" + 
                    "order by count(forums.id) desc;";
    
            Connection conn = null;
            ResultSet result = null;
            PreparedStatement stat = null;
    
            try {
                conn = dataSource.getConnection();
    
    
                stat = dataSource.getConnection()
                        .prepareStatement(query);
    
    
                result = stat.executeQuery();
    
                List<String> res = new ArrayList<String>();
    
                while(result.next()) {
                    res.add(result.getString("id"));
                }
    
                return res;
    
            } catch (SQLException e) {
                return null;
            }
    
            finally {
                CloseDbResources(conn, stat, result);
            }           
        }



    Le risorse unmanaged vengono ripulite.

    protected void CloseDbResources(Connection connection, PreparedStatement preparedStatement, ResultSet resultSet) {
            if (resultSet != null) {
                try {
                    resultSet.close();
                } catch (SQLException e) { }
            }
            if (preparedStatement != null) {
                try {
                    preparedStatement.close();
                } catch (SQLException e) { }
            }
            if (connection != null) {
                try {
                    connection.close();
                } catch (SQLException e) { }
            }
        }



    Le classe MiscDAO (che contiene la query) viene istanziata dalla DAOFactory, che è un singleton. Il metodo init (che inizalizza la classe per interfacciarsi al database) viene chiamato una solo una volta, nel momento in cui la classe viene istanziata... e siccome il metodo init è privato, siamo sicuri che non possa essere chiamato da fuori.

    static synchronized DAOFactory getInstance() {
            if (instance == null) {
                String persistenceName = FdTConfig.getProperty("persistence.name");
                try {
                    instance = new DAOFactory();
                    instance.init(FdTConfig.getDatabaseConfig(persistenceName));
                } catch (Exception e) {
                    LOG.fatal("Cannot instantiate Persistence '" + persistenceName + "'", e);
                    return null;
                }
            }
            return instance;
        }


    void init(Properties databaseConfig) throws ClassNotFoundException {
            String driver = databaseConfig.getProperty("driverclass");
            Class.forName(driver);
    
            String username = databaseConfig.getProperty("username");
            String password = databaseConfig.getProperty("password");
            String url = databaseConfig.getProperty("url");
    
            dataSource = new BasicDataSource();
            dataSource.setMaxTotal(15);
            dataSource.setMaxIdle(10);
            dataSource.setMinIdle(3);
            dataSource.setMaxWaitMillis(30000);
            dataSource.setTestOnBorrow(true);
            dataSource.setTestWhileIdle(true);
            dataSource.setUrl(url);
            dataSource.setUsername(username);
            dataSource.setPassword(password);
            dataSource.setValidationQuery("SELECT 1");
            dataSource.setValidationQueryTimeout(30);
    
    
    
            DSLContext jooq = DSL.using(dataSource, SQLDialect.MYSQL);
    
            authorsDAO = new AuthorsDAO(jooq);
            threadsDAO = new ThreadsDAO(jooq);
            messagesDAO = new MessagesDAO(jooq);
            pollsDAO = new PollsDAO(jooq);
            quotesDAO = new QuotesDAO(jooq);
            bookmarksDAO = new BookmarksDAO(jooq);
            adminDAO = new AdminDAO(jooq);
            miscDAO = new MiscDAO(jooq, dataSource);
            privateMsgDAO = new PrivateMsgDAO(jooq);
            digestDAO = new DigestDAO(jooq);
            loginsDAO = new LoginsDAO(jooq);
        }



    Per risolvere il bug (speriamo) è stato in pratica sufficiente riscrivere il metodo getForums in questa maniera, cioè utilizzando JOOQ.

    public List<String> getForums() {
    
    		
    		Result<Record1<String>> records = jooq.select(FORUMS.ID)
    				.from(FORUMS)
    				.leftOuterJoin(MESSAGES)
    				.on(FORUMS.ID.eq(MESSAGES.FORUM))
    				.groupBy(FORUMS.ID)
    				.orderBy(DSL.count(FORUMS.ID).desc())
    				.fetch();
    		
    
    		List<String> res = new ArrayList<String>(records.size());
    		for (Record1<String> record : records) {
    			res.add(record.getValue(FORUMS.ID));
    		}
    		
    		return res;
    	}



    Ora, a me interessa MOLTO capire l'errore commesso nella precedente versione, perché sbagliando e analizzando l'errore si impara.

    Sono curioso di sentire la spiegazione del frocetto snowfloake e dello svizzero strapagato per fare database di merda.
    • Avatar
      Scritto da
      Non Autenticato
      il 2018-04-03 15:04:04.0 alle 2018-04-03 15:04:04.0
      Re: Mentre i due snowflake starnazzano
      Rianalizzando un po' la questione, sono arrivato a questa ipotesi...

      Il codice che ho scritto (e che ho messo qui sopra) era corretto, solo che non era quello che stava girando.

      Due giorni fa ho scritto il codice per fare in modo che un utente possa rispondere nella sezione Admin: http://www.forumdeitroll.com:3001/?p=FdtDueZero.gi...

      Stranamente dopo il commit e il deployement del nuovo war, rispondere nella sezione Admin non era ancora possibile... e io mi sono messo a rileggere il codice per capire cosa non funzionasse.

      Ieri ho nuovamente deployato il war al server (senza cambiare nulla nel codice) ed ecco che finalmente la feature che permette di rispondere nella sezione Admin si è attivata.

      Conclusione: per qualche motivo a me sconosciuto, tomcat non si è preso il war che gli ho sparato nel culo, ma continuava a eseguire il vecchio codice (da dove cazzo lo prendeva??).

      Sospetto quindi che sia successo lo stesso con la query. In una prima versione del codice delle tre risorse da ripulire, ne veniva ripulita solo una (credevo che bisognava ripulire solo la classe Connection) e nonostante io abbia corretto l'errore nel codice, il server non si è preso il war che gli ho sparato nel culo e perciò girava una versione del codice in cui certe risorse, non venendo ripulite, si accumulavano fino a rendere problematico l'accesso al database.

      Nei prossimi giorni vorrei riprovare a rimettere il codice sopra, assicurandomi che questa volta venga correttamente deployato. In questo modo verifico la mia ipotesi e togliermi la spina dal piede. Lo farò durante la giornata così posso stare vigile sul forum e intervenire non appena avviene un memory leak.
<softv>

Pagina generata in 22 millisecondi

Utenti attivi: 13 nell'ultimo minuto, 38 negli ultimi cinque minuti, 69 negli ultimi 15 minuti