venerdì 27 dicembre 2013

Oracle SQL Developer e gli altri

Mi sono accorto di una cosa curiosa, e tutto sommato neanche direttamente correlata a PostgreSQL: Oracle SQL Developer, il client grafico basato su tecnologia Java e gratuitamente disponibile agli utenti, permette la connessione a database anche non-Oracle. E la cosa viene ben evidenziata dai tip-of-the-day visualizzati all'avvio.



Peccato che fra gli assenti spicchi proprio l'elefante, che sia solo un caso?

lunedì 23 dicembre 2013

Magit migliorato ancora!

Era da un po' di tempo che non aggiornavo la mia versione di Magit, il front-end git per Emacs, e devo dire che sono rimasto molto colpito dallo sviluppo costante e accurato che il progetto ha avuto.
Certo, Magit non semplifica la vita a chi non conosce git, anzi è necessario conoscere bene il workflow di git per poter lavorare in Magit, ma la nuova gestione è veramente migliorata ed aiuta a districarsi fra le varie opzioni.
Infatti ora è disponibile un buffer con le abbreviazioni dei principali comandi, in modo da semplificare la scelta delle opzioni da seguire. Inoltre c'è un uso molto calibrato dei colori nei buffer, tanto che anche il buffer del commento di commit ora utilizza differenti colori per indicare le sezioni ignorate e quelle di testo effettivo. E a proposito del buffer dei commenti di commit: viene abilitato in default il flyspell (ovvero lo spellchecking al volo con evidenziazione delle parole sbagliate).
Complimenti agli sviluppatori per questo fantastico front-end!

Event Triggers & pl/perl

Nella versione 9.3 di PostgreSQL sono stati introdotti gli event-triggers, trigger che agiscono a livello di DDL (e non solo di DML).
Come ben noto, il legame fra PostgreSQL e Perl è stretto, e ben presto (circa 10 giorni fa) sono stati abilitati i trigger ad eventi anche in pl/perl, il linguaggio procedurale Perl integrato nel server PostgreSQL. Un interessante articolo apparso sul planet illustra alcune delle possibilità.

domenica 1 dicembre 2013

Numeri strani

Quando sono salito in auto la mia attenzione è stata nuovamente colpita dai numeri sul contachilometri. Se mi fossi fermato a 333.55 la sequenza sarebbe stata perfetta!


sabato 30 novembre 2013

Microkernel(s)

Quite often I find on the web threads related to the "microkernel" cutlure versus the "monolithic" kernel one.
First of all, I have to say I'm not an expert in the former, but I would like to provide some insights from what my experience has been so far about the two approaches.

Please consider we are not really and strictly talking about Operating Systems kernels here: the approach can be extended to pretty much every complex software system.
So what is a microkernel architecture? Essentially it is a complex system made up by small pieces that cooperates and coordinates each other; each component is pluggable and can be substituted without a whole system reboot or downtime. The key point here is that EVERY component can be replaced/upgraded at run-time without having to stop the system as a whole.
In order to achieve this run-time behavior, the system must provide a strong decoupling of modules via a kind of message-passing scheme, and therefore we could state that the messaging delivery system is the only one that is going to require a whole reboot when changed.

The most famous Operting System based on microkernel is Minix, but this is only a huge example of this kind of architecture. OSGi is another example of a dynamic system where pretty much everything can be plugged at run-time. STREAMS, the old SunOS networking layer was also based on such concept. Erlang reminds me a microkernel architecture.

Are microkernel systems good or bad? It depends. When the task has to be low level, microkernels are generally bad. As an evidence of this, even if Minix is still under active development, all the rest of the world has chosen another approach, and I believe that if great OSs like FreeBSD, OpenBSD, Linux have chosen and still continue to resist to microkernel, they cannot be totally wrong.
STREAMS have been kicked off as soon as the network load increased, due to the performance lack.
On the other hands, OSGi is very succesfull, being the system not a low level one. The same role/agents systems I developed during my research activity could have been thought of a microkernel kind of systems, and while they were very dynamic, performances were not so good as a statically bound system.

So what?
If dynamism and pluggable features are the most important parts of your project, go for a microkernel approach. If performance is your aim, avoid a microkernel.
This is my personal opinion.

mercoledì 27 novembre 2013

Editor di testi

Aron Seigo ha pubblicato un interessante post nel quale parla della sua "conversione" da Vim a Kate, l'editor di default dell'ambiente KDE (per chi non lo sapesse, Seigo e' stato il leader dello sviluppo della versione 4 di KDE).
Tre sono fondamentalmente le motivazioni del passaggio da Vim a KDE: (i) scorciatoie simili, (ii) la possibilita' di avere delle sessioni, ossia una sorta di project management per gruppi di file e (iii) la console integrata.

L'aspetto degli editor mi tocca sempre profondamente, anche perche' l'editor di testi e' effettivamente lo strumento piu' usato da uno sviluppatore software (e anche dai sysadmin). Francamente sono abituato a Emacs e tendo a vedere negativamente ogni altra possibilita'. Si tratta certamente di una mia inclinazione e preferenza, ma Emacs e' a tutti gli effetti uno di quegli strumenti che mi permette di fare tutto e, cosa non trascurabile, funziona su qualunque piattaforma io debba lavorare. E con piattaforma non intendo solo il sistema operativo/architettura, ma anche il sistema grafico (che potrebbe anche essere assente).
Purtroppo Emacs sta diventando, a mio avviso, sempre piu' un sistema per abitudinari, e questo fara' si che molte delle feature interessanti non vengano portate su Emacs facilmente.
Tuttavia continuo ad essere molto soddisfatto di Emacs, che fino ad ora mi permette di avere una interfaccia unificata verso file system, sviluppo di software, editing di testo e shell.

Questione di gusti.

lunedì 25 novembre 2013

Addio e grazie per tutto il pesce

Mi è sembrata la citazione migliore per salutare Charlie.

domenica 17 novembre 2013

Disabilitare un indice in PostgreSQL

Ho gia' scritto in precedenti post come PostgreSQL sia un database fortemente orientato al catalogo: ogni azione che il database esegue e' fortemente dipendente dal catalogo di sistema.
Anche gli indici usabili lo sono, ed essere a conoscenza di come disabilitare temporaneamente un indice puo' risultare molto importante. PostgreSQL infatti non mette a disposizione, per scelta, i "query hints", ovvero non e' possibile specificare con quale indice PostgreSQL deve forzatamente eseguire una query. Come conseguenza, a volte puo' risultare molto complicato valutare l'efficacia di un indice, e spesso il modo che si usa e' quello di disabilitare, a livello di intero cluster, alcuni metodi di accesso. Ma ecco che tramite il catalogo di sistema e' possibile inibire un singolo indice al fine di escluderlo dalle scelte possibili dell'ottimizzatore, e quindi di valutare gli indici rimanenti.

Per prima cosa si crei un semplice use case fatto da una sola tabella piena di tuple casuali:

CREATE TABLE people( name text,
surname text,
pk serial not null,
primary key(pk) );
INSERT INTO people( pk, name, surname )
SELECT generate_series(1, 100000),
md5( random()::text ),
md5( random()::text );

Si passi poi alla creazione di due indici sui campi della tabella:

CREATE INDEX name_idx ON people(name);
CREATE INDEX surname_idx ON people(surname);

E' ora possibile verificare che uno dei due indici viene usato in query sufficientemente filtranti:

EXPLAIN SELECT surname, name FROM people WHERE surname like 'f%';
QUERY PLAN
-----------------------------------------------------------------------------
Bitmap Heap Scan on people (cost=21.54..967.48 rows=500 width=64)
Filter: (surname ~~ 'f%'::text)
-> Bitmap Index Scan on surname_idx (cost=0.00..21.42 rows=500 width=0)
Index Cond: ((surname >= 'f'::text) AND (surname < 'g'::text)) 


 Il catalogo di sistema pg_index fornisce informazioni circa la disponibilita' degli indici su ogni tabella, e quindi e' possibile ottenere lo stato "attuale" degli indici per una tabella specifica con una query simile alla seguente:

SELECT cc.relname, indexrelid, indnatts, indisclustered, indisvalid, indisready FROM pg_index JOIN pg_class c ON c.oid = indrelid JOIN pg_class cc ON indexrelid = cc.oid WHERE c.relname = 'people' AND c.relkind = 'r' AND cc.relkind = 'i'; 

relname | indexrelid | indnatts | indisclustered | indisvalid | indisready -------------+------------+----------+----------------+------------+------------ people_pkey | 16541 | 1 | f | t | t 
name_idx | 16558 | 1 | f | t | t 
surname_idx | 16559 | 1 | f | t | t 

La colonna indnatts indica quanti attributi della tabella fanno parte dell'indice; la colonna indisclustered indica la cluster-ness dell'indice, o meglio se la tabella e' ordinata in base a questo indice. La colonna indisvalid e' quella forse piu' importante: indica se l'indice e' usabile dall'ottimizzatore, o meglio se usabile in modo "sicuro". In altre parole, un valore false in questa colonna indica che l'indice al momento non deve essere preso in considerazione perche', ad esempio, una operazione di INSERT/UPDATE sulla tabella e' ancora in corso e a seguito di questa l'indice deve essere riorganizzato. L'ultima colonna mostrata, indisready, indica se l'indice e' pronto a subire modifiche, ossia puo' essere aggiornato a seguito di modifiche nella tabella che referenzia. Da quanto descritto sopra si puo' concludere che indisvalid contribuisce a dare "visibilita'" e "validita'" all'indice, e quindi valori false nelle colonne indicano a PostgreSQL di ignorare l'indice. E' facile verificare quanto appena detto disabilitando un indice nel catalogo di sistema (ammesso che sia super utente): 


UPDATE pg_index SET indisvalid = false WHERE indexrelid = 16559; e il piano di esecuzione ora cambia: EXPLAIN SELECT surname, name FROM people WHERE surname like 'f%'; QUERY PLAN ------------------------------------------------------------ 
Seq Scan on people (cost=0.00..2485.00 rows=500 width=64) 


Con questa semplice modifica al catalogo e' quindi possibile verificare altri indici, scartati a priori dall'ottimizzatore, senza intaccare il funzionamento dell'intero cluster. Si noti che l'ottimizzatore di PostgreSQL e' molto bravo nel fare il suo lavoro, e quindi se ha deciso di scartare altri metodi di accesso e' quasi certo che questi ultimi siano poco efficienti. E' possibile verificare il comportamento degli indici anche a seguito di una operazione di UPDATE: 

EXPLAIN UPDATE people SET surname = 'TEST' WHERE surname like 'f%'; QUERY PLAN ------------------------------------------------------------------ Update on people (cost=0.00..2485.00 rows=500 width=42) -> Seq Scan on people (cost=0.00..2485.00 rows=500 width=42)
Filter: (surname ~~ 'f%'::text)

e riabilitando l'indice si ottiene che questo viene nuovamente usato:

UPDATE pg_index SET indisvalid = true WHERE indexrelid = 16559;
EXPLAIN UPDATE people SET surname = 'TEST' WHERE surname like 'f%';
QUERY PLAN
-----------------------------------------------------------------------------------
Update on people (cost=21.54..967.48 rows=500 width=42)
-> Bitmap Heap Scan on people (cost=21.54..967.48 rows=500 width=42)
Filter: (surname ~~ 'f%'::text)
-> Bitmap Index Scan on surname_idx (cost=0.00..21.42 rows=500 width=0)
Index Cond: ((surname >= 'f'::text) AND (surname < 'g'::text))

What is (for me) Open Source?

A few weeks ago I was doing an interview about the past PGDay.IT, the national event related to PostgreSQL; the very last question of such interview was about my understanding of Open Source.
Well, it is not simple to give a quick answer to this question, and therefore I try to write down some thoughts about what I believe it is the Open Source.

My opinion is that Open Source is not fully related to writing code and programs, it is more a mindset. Open Source means curiosity, the will to learn something more, to understand how a piece of the world is working.
Everyone, at least one time in his whole life, has opened some piece of hardware: the computer, the VHS, the car hood, a lamp, and so on. This is the Open Source mindset: curiosity to explore how something become a working thing. And this curiosity is what makes  a professional: the need to understand something more, that will help him to acquire new knowledge and, therefore, to be able to apply such knowledge in his day-by-day work.

The above is the real important part of Open Source: it is a culture, not a technique!

Now, Open Source has also several myths, the most common one being that since the "code" is open, it can be audit by so many users and experts that is has to be 100% correct.
This is not my opinion.
First of all, complex code requires very high skills and context knowledge, and therefore it does not mean anything releasing the code as Open Source if only a few people are able to "understand" such code.
Second, being available to everyone does not mean that anyone is interested in reading the code.
Therefore, Open Source code is not a silver bullet for quality, but rather a starting point to get new ideas (let's call the branches) and new improvements from other people.

What about the money? Well, Open Source is generally cheaper than proprietary software, and this is often good except when the management start thinking that if it does not cost anything it means it is not worthing at all (a quite common mindset in my opinion). The key point here is different: it is not the fact that Open Source does not cost anything, it does cost, but often for related services. That is: "take this software and use if for free, and if you need some assistance please hire me and I will help". Does it mean that the for-free version is a low quality one? It depends on who is making it available for free, but generally it is not.

Last but not least, a small thought: does really exist proprietary software? After all, almost every software is created, maintained and improved by different programmers, that means there are several people knowing how the software works. And this makes the software not-proprietary, or better, proprietary to other people. In other words, there is not a real proprietary software, there are only people giving up their rights.

sabato 16 novembre 2013

MySQL Workbench e "safe mode"

MySQL Workbench ha una funzione a mio avviso estremamente irritante: viene impedito l'UPDATE o la DELETE di tuple che non siano referenziate tramite la loro chiave.
Altri programmi seguono approcci simili, ma piu' razionali. Ne e' un esempio l'autocommit (che anche lo stesso MySQL Workbench implementa): di fatto si richiede all'utente di fare un commit esplicito al termine di uno statement per prevenire l'accidentale perdita/modifica di dati.
Ma il "safe mode" usato da MySQL Workbench che previene UDPATE/DELETE con query che non referenzino le chiavi e' molto piu' fastidiosa: di fatto si costringe l'utente ad andare nelle impostazioni del programma per cambiarne il comportamento, cosa che non puo' quindi essere agilmente modificata in una sessione di lavoro che preveda piu' query.


Apprezzo lo sforzo di MySQL di impedire errori accidentali e frettolosi, ma onestamente penso che questa ennesima feature anti-DBA non ponga a favore dell'ecosistema stesso.

venerdì 15 novembre 2013

KMail, KDE e la directory della posta

Ormai sono piu' di 10 anni che uso fedelmente KDE come desktop environment.
Mi piace, funziona bene, mi trovo bene, e anche se ne esistono di piu' leggeri e semplici, lo preferisco a molti competitor anche commerciali.
La mia passione per il programma di posta elettronica, KMail, si e' andata affievolendo negli anni. Non che il programma abbia perso in qualita', ma semplicemente mi sono mosso verso un approccio maggiormente Web per riuscire a tenere ordine fra tutti i computer che uso. Insomma, un po' piu' di cloud.
Ma uso ancora KMail, e fino ad ora non avevo mai avuto problemi. Fare il backup della posta era una operazione semplice e quasi indolore, e in linea con la filosofia Unix si trattava di poco piu' che un tarball ben assestato.
Eppure nelle ultime versioni di KDE/KMail qualcosa e' cambiato, e in modo anche abbastanza silenzioso oserei dire.
La cartella della posta di un utente non risiede piu' in ~/Mail, come ci si potrebbe aspettare, ma in una cartella nascosta ~/.local che il KDE usa appunto per lo storing dei dati delle applicazioni.

Nulla in contrario, basta sapere cosa si deve cercare, ma onestamente penso che la scelta sia idiota (e difficilmente mi sentirete mai dare addosso a KDE!).

Anzitutto KDE ha gia' una cartella privata, che e' ~/.kde, e quindi non vedo l'esigenza di averne una differente. Ma anche ammesso che questo sia un modo per tenere configurazioni e dati separati, approccio piu' che comprensibile, non vedo perche' creare una cartella nascosta ~/.local. E ancora di piu' non capisco come mai ~/.kde non abbia un link a ~/.local in modo da permettere almeno un salvataggio dei file attraverso i link.
Mi ricorda molto l'approccio Microsoft Windows con la "Application Data" in ogni home utente.

La morale di quanto scritto sopra? Fare sempre un backup accurato dell'intera directory home!
Non si puo' sbagliare.

PostgreSQL su Amazon RDS

Sono molti i post che indicano la novità in casa Amazon RDS, ossia il supporto a PostgreSQL 9.3.1, come riportato ufficialmente:

Amazon RDS supports DB instances running PostgreSQL 9.3.1. You can create DB instances and DB snapshots, point-in-time restores and backups.

Si noti che Amazon permetteva già l'uso di PostgreSQL in EC2, ma l'accettazione di PostgreSQL nel Relational Database Service (RDS) rappresenta una vera innovazione.
Inoltre pare che la versione usata da Amazon sia un vero e proprio fork di PostgreSQL.

Cinque volte cinque

Qualche giorno fa, mentre ero fermo attendendo il pieno di carburante, ho notato una cosa curiosa sul contachilometri della mia macchina.


martedì 12 novembre 2013

PostgreSQL e uso dello spazio di storage

PostgreSQL tenta di minimizzare, o meglio di ritardare il piu' possibile, gli accessi allo storage fisico. In questo port voglio mostrare come anche una operazione apparentemente banale come la cancellazione di una colonna da una tabella non produca immediati effetti su disco.
 
Per prima cosa occorre creare una tabella di esempio da popolare con un po' di dati di prova per valutare come cambi l'uso dello storage secondo le modifiche alla struttura della tabella stessa:

CREATE TABLE dropping_test( pk SERIAL NOT NULL, description text, PRIMARY KEY(pk) );



WITH RECURSIVE counter(pk) AS
( SELECT 1 UNION SELECT pk + 1 
  FROM counter WHERE pk < 1000000 )
INSERT INTO dropping_test(pk, description)
SELECT c.pk, 'A fake description for entry ' || c.pk
FROM counter c;



La query di cui sopra vuota la tabella e la riempie di un milione di tuple sostanzialmente identiche. La dimensione finale della tabella risulta essere di circa 60 MB:

SELECT pg_size_pretty( pg_relation_size( 'dropping_test' ) );
pg_size_pretty
----------------
65 MB


A questo punto si puo' procedere alla rimozione della colonna description, che e' quella che occupa la maggior parte dello spazio di storage essendo formata da testo libero. Da notare che dopo la rimozione della colonna il catalogo di sistema mostra l'attributo (colonna) come "deprecato". Cio' significa che l'attributo e' stato eliminato logicamente dalla tabella ma non fisicamente (poiche' ancora presente nel catalogo di sistema).


ALTER TABLE dropping_test DROP COLUMN description;
ALTER TABLE
Time: 92.774 ms


Da notare la velocita' di eliminazione (logica) della colonna: di fatto non e' successo molto sullo storage, e quindi il sistema non ha perso tempo nel rimuovere la colonna.
Una colonna rimossa diventa sostanzialmente invisibile al parser, ossia non e' usabile lato SQL. Se si interroga il catalogo di sistema si ottiene l'informazioni circa la rimozione della colonna, che pero' ha perso il proprio nome (il drop di una colonna non e' una operazione recuperabile):

SELECT attname, attisdropped FROM pg_attribute a JOIN pg_class c ON a.attrelid = c.oid WHERE c.relname = 'dropping_test';

attname | attisdropped
------------------------------+--------------
tableoid | f
cmax | f
xmax | f
cmin | f
xmin | f
ctid | f
pk | f
........pg.dropped.2........ | t


In realta', se e' vero che si e' perso il nome della colonna, si ha qualche informazione circa la sua posizione: il nome nel catalogo degli attributi riporta la posizione ordinale della colonna appena eliminata. In altre parole, 'pg.dropped.2' indica che e' stata eliminata la colonna numero 2 della tabella, come si puo' evincere dal file sorgente heap.c:

/*
* Change the column name to something 
* that isn't likely to conflict
*/
snprintf(newattname, sizeof(newattname),
"........pg.dropped.%d........", attnum);


E la tabella, dal punto di vista fisico, come e' cambiata? Di fatto non e' cambiata, visto che lo storage non e' stato toccato:

SELECT pg_size_pretty( pg_relation_size( 'dropping_test' ) ); pg_size_pretty
----------------
65 MB


A questo punto si puo' far intervenire vacuum per vedere cosa succede lato fisico e logico; in particolare il processo di vacuuming andra' a riscrivere le pagine dati rimuovendo lo spazio occupato dalla colonna rimossa. Il risultato, al termine dell'operazione, e' una riduzione della dimensione della tabelle e la scomparsa dell'attributo droppato nel catalogo di sistema:

VACUUM FULL VERBOSE dropping_test;
INFO: vacuuming "public.dropping_test"
INFO: "dropping_test": found 0 removable, 1000000 nonremovable row versions in 8334 pages
DETAIL: 0 dead row versions cannot be removed yet.
CPU 0.61s/0.53u sec elapsed 2.29 sec.
VACUUM
Time: 4593.219 ms

Che ci porta ad avere una tabella "compressa":

SELECT pg_size_pretty( pg_relation_size( 'dropping_test' ) );
pg_size_pretty
----------------
31 MB



Si presti attenzione: tutto questo e' stato possibile perche' autovacuum era disabilitato:

SHOW autovacuum;
autovacuum
------------
off

Se autovacuum fosse stato attivo, come normalmente e', la riorganizzazione della tabella sarebbe avvenuta quasi subito e quindi la dimensione della tabella sarebbe cambiata sotto al naso dell'operatore.

Si noti che l'operazione inversa, l'aggiunta di una colonna, si comporta sostanzialmente in modo analogo: quando viene aggiunta una colonna il sistema memorizza nel catalogo la disponibilita' della nuova colonna, ma non opera sullo storage.

ALTER TABLE dropping_test ADD COLUMN description text;
ALTER TABLE
Time: 19.337 ms

SELECT pg_size_pretty( pg_relation_size( 'dropping_test' ) );
pg_size_pretty
----------------
31 MB

E si noti anche che la scrittura di una tupla non implica la riorganizzazione di tutta la tabella: di fatto, grazie ad MVCC, le tuple "nuove" sono in append sui dati e quindi le tuple "vecchie", prive di colonna aggiunta, non vengono riorganizzate:

UPDATE dropping_test 
SET description = 'Hello World' WHERE pk = 1;

SELECT pg_size_pretty( pg_relation_size( 'dropping_test' ) );
pg_size_pretty
----------------
31 MB

Discorso differente se si aggiunge una colonna con valore di default, cosa che forza il sistema a scrivere il valore di default su ogni tupla e quindi ad invalidare ogni tupla vecchia con conseguente raddoppiamento delle tuple e aumento di spazio:

ALTER TABLE dropping_test 
ADD COLUMN description_initialized text 
default 'A fake description as default here!';
ALTER TABLE
Time: 4356.180 ms

SELECT pg_size_pretty( pg_relation_size( 'dropping_test' ) ); pg_size_pretty
----------------
65 MB

In conclusione, PostgreSQL cerca di utilizzare lo storage fisico in modo molto efficiente ritardando il piu' possibile le scritture (o riscritture) su disco. Ancora una volta si evince come il comportamento di PostgreSQL sia molto guidato dal catalogo di sistema.

domenica 10 novembre 2013

PGDay.IT 2013: una cosa che mi sono scordato

Il PGDay.IT 2013 è stato un vero successo, ormai è fuori discussione.
Nelle settimane seguenti ho avuto la possibilità di realizzare due interviste, una in italiano e una in inglese, sull'andamento dell'evento e della community ITPUG.
Le interviste sono state fatte a me, ma ci tengo a precisare che il lavoro dietro al PGDay.IT 2013 e ad ITPUG non è solo farina del mio sacco, bens^ di tutti gli amici e colleghi del consiglio direttivo nonché dei soci volontari.

In questi giorni stiamo anche pubblicando le video interviste realizzate all'evento. Guardando quella relativa ad ITPUG Lab, che ritrae me e Gianluca, mi è tornata in mente una cosa che non ricordavo piu': la stanchezza di quella giornata maturata durante i preparativi all'evento.
Ma la soddisfazione supera di slancio qualche ora di sonno persa!



Cara Trenitalia....

Cara Trenitalia,
sono sempre io, un viaggiatore che nonostante tutti i maltrattamenti ricevuti continua a prenotare biglietti con la speranza di riuscire a usare i tuoi mezzi.
Ammetto pero' che nell'ultimo periodo mi hai messo a dura prova.
Ebbene si, perche' mi obblighi ad acquistare i biglietti prima usando un sistema Web di dubbia funzionalita', al fine di poter usufruire degli sconti il cui solo scopo sembra quello di farmi sentire uno stracciano, visti tutti i "warning" che compaiono e che mi indicano di scegliere una tariffa piu' costosa.
Mi forzi ad arrivare puntuale, anzi in anticipo, per poter prendere posto in treni sporchi e, molto spesso, sudici.
E nonostante questo, io che ancora accetto e preferisco di viaggiare in treno, sono pure maltrattato.

Negli ultimi sei mesi mi sono recato due volte a Prato, quindi un viaggio (Modena-Prato) di circa 1,5 ore. Entrambe le volte ho prenotato degli Intercity, che mi pare di capire siano treni di tutto rispetto. Ma sui 4 viaggi complessivi, solo uno e' stato puntuale, e negli altri casi ci sono stati ritardi rispettivamente di 10 minuti, 30 minuti e 45 minuti.

Ora comprenderai, cara Trenitalia, che piu' di 30 minuti di ritardo su un treno che ne dura circa 90 sono inaccettabili. E ovviamente diritto al rimborso, stando al tuo fantastico sistema Web di prenotazione e gestione, neanche a parlarne!

Ma diciamo pure che sono stato io sfortunato, e che ho scelto due giornate particolarmente sfortunate, seppur feriali.
Altri treni quindi viaggeranno sicuramente con maggiore puntualita'!
Non e' pero' il caso del famigerato "Gigetto", collegamento Modena-Sassuolo. Si, lo so che ufficialmente quello e' un treno RTPER e non Trenitalia, ma non sono molto esperto e me un "treno" vale l'altro. Tanto piu' che i treni TPER transitano nelle stazioni Trenitalia, le quali si scordano di avvisare i viaggiatori TPER di eventuali disguidi tecnici.
Su tutti i monitor luminosi si vedono infatti informazioni circa treni TPER in partenza, e una voce metallica dall'altoparlante non fa che ricordarci che se non saliamo subito sul treno lo perderemo...ma il treno non e' sui binari! E arriva, con calma, 25 minuti dopo. O vogliamo forse ricordare le innumerevoli volte che il treno viene sostituito dall'autobus, che aspetta esattamente 1 minuto oltre l'orario ufficiale prima di partire dal piazzale piu' lontano di tutta la stazione?

Insomma, cara Trenitalia, ma perche' ogni tanto non provi anche tu a viaggiare con i tuoi stessi mezzi per vedere se il servizio e' veramente cosi' soddisfacente?

sabato 9 novembre 2013

Room Number 621: EuroBSDCon!

I attended the Euro BSD 2013 in Malta, on the last week of September.


The conference was a great mix of technical and social knowledge and represents a great opportunity to meet, talk and learn directly from the /Unix-gods/ of any time and nation. For instance, I was sitting near the legendary McKusick while listening the great Theo De Raadt during his keynote about the time_t overflow problem.

I had the great opportunity to see and meet people I've only seen as names on mailing lists, and the technical quality of many of the talks was really good. Several talks were related to the [[http://www.openbsd.org][OpenBSD]] project, and I have to say I'm every day more interested in this project more for its policy than for its technology; but this is another story.

I had nothing but good words to say about the event and the organization, and definetely was worth being there.
I had also the opportunity to visit (again) Malta, which is a very nice place to be and to spend a few days.

venerdì 8 novembre 2013

Room Number 236: PGDay.IT 2013

PGDay.IT 2013: un successo!


Non saprei come altro iniziare questo post relativo alla conferenza annuale dedicata a PostgreSQL. E' chiaro, sono di parte, anche perche' ormai faccio parte del comitato di organizzazione dalla prima edizione, e quindi da 7 anni.
Ma il successo di questa edizione e' stato proclamato a gran voce dai partecipanti, come e' giusto che sia.
Sia chiaro, non e' stato un PGDay.IT perfetto, sono stati commessi alcuni errori, ma il risultato complessivo e' stato ottimo.



Tante le novita' introdotte con questa edizione, fra le quali spicca il primo ITPUG Lab, e lasciatemelo dire, era ora!
 Il Lab e' stata una sessione parzialmente derivata dall'OST che ha "spinto" i partecipanti a mettere le mani su problemi e tematiche concrete, da loro stessi proposte, in un ambiente collaborativo ove vari team si applicavano per il raggiungimento di uno scopo. Finalmente una sessione realmente aggregante e soprattutto non passiva! E a detta dei partecipanti l'idea (non totalmente mia) e' stata una piacevole e utile novita'.

Altra grossa novita' il live streaming, che penso abbia contribuito sia a far conoscere ed apprezzare PostgreSQL che l'ottimo lavoro di ITPUG.

La conferenza e' stata tenuta da speaker professionali e preparati, e il contenuto tecnico e' stato eccellente. Ospiti d'onore Bruce Momjian (che fra gli altri ha fatto anche il discorso di apertura) e David Fetter.

La partecipazione e' stata da record: 91 persone.
L'associazione ha ritrovato vigore e nuovi soci si sono uniti alla famiglia ITPUG.
La birra non e' mancata, grazie anche agli amici che hanno sponsorizzato l'evento; anche la Fiorentina non e' stata risparmiata e scherzando posso dire che ormai ogni anno la riunione degli "elefanti" provoca la morte di qualche innocente mucca...

Sono fiducioso che tutto lo staff e i componenti ITPUG continueranno a lavorare bene.
Al momento sono ancora molto preso dalla conclusione lavori, e quindi non ho il tempo e le energie per fornire un resoconto piu' dettagliato dell'evento.

martedì 22 ottobre 2013

PGDay.IT 2013: ci siamo!

Ormai manca veramente pochissimo, e fra le tante novità introdotte con questa edizione c'è anche il live streaming (di una parte) della conferenza!
Altra novità che mi sta molto a cuore è il primo ITPUG Lab.


domenica 15 settembre 2013

Esce pfSense 2.1

E' stato annunciato oggi pfSense 2.1, la nuova major release del sistema di firewalling, routing, vpn basato su FreeBSD: Fra le varie novità di networking si trovano un aumentato supporto per IPV6 e anche il supporto nativo al formato PBI (Push Button Installer) creato per PCBSD.
La release note ufficiale si trova qui.


Klipper e l'odioso problema dei menu' popup

A seguito di un normale aggiornamento, il KDE 4.11 ha deciso di attivare una funzione per me odiosa e insidiosa: i menu' a popup di klipper.
La funzione si attiva o disattiva selezionando la voce Enable Clipboard Actions nel menu' a popup di klipper:


L'effetto è quello di avere dei menu' a scomparsa (popup) ad ogni azione che potrebbe riguardare la clipboard, come ad esempio la selezione della barra degli indirizzi del browser, che apre appunto un HTML Action menu:



La cosa è a mio avviso estremamente fastidiosa e poco utile, anche perché rischia di aprire programmi e svolgere azioni assolutamente prive di significato. Ad esempio io spesso mi sono trovato ad aprire Emacs passandogli un URL (forse perché ho w3c installato).
Ho disabilitato quanto prima questo comportamento, ed è una cosa che consiglio a tutti gli utenti.

sabato 14 settembre 2013

Il 9/9 è uscita la 9.3!

Il 9 Settembre è uscito PostgreSQL 9.3! Notavo come la scelta della data di uscita, il 9/9, unito alla versione abbia un simpatico gioco numerico:
il 9/9 è uscito PostgreSQL 9.3
le uniche due cifre che compaiono nella frase di cui sopra sono il 9 e il 3, e incidentalmente il 9 compare esattamente 3 volte, da cui 9.3!

Tornando seri, ecco il link alle release note.
Molte le funzionalità aggiunte a questa versione, fra le quali il checksum sulle pagine dati, il LATERAL join, le viste aggiornabili e i foreign data wrapper scrivibili che danno il via alla federazione di database.

Tanti auguri

Ne è passato di tempo da quando io ed Enrico abbiamo iniziato a condividere l'ufficio a Sassuolo. Non posso dire di essere cresciuto con Enrico, anche se di anni fianco a fianco sul lavoro ne abbiamo passati davvero tanti. Quante risate, quante arrabbiature, quanti mal di testa che abbiamo condiviso fra i cavi di switch e router e fra le telefonate degli utenti inferociti.
Poi ci si è un po' persi di vista, ma l'amicizia al contrario del latte non ha scadenza e quella rimane inalterata.
E oggi ho assisitito ad uno dei matrimoni piu' belli: quello di Enrico e della sua Patrizia. Già sua, perché non la perde di vista neanche un momento (e lei fa altrettanto).
Unico rammarico: la loro distanza.
Ma tanta gioia per questo momento importante e un sincero augurio di tanto successo.

PGDay.IT 2013: avanti tutta!

L'organizzazione del PGDay.IT 2013 sta procedendo senza grossi intoppi: c'è una lista di talk ricca e completa, nonché una lista di sponsor e patrocini importante e di peso. Sono sicuro sarà anche questa volta un evento di successo.

Ci sono tante piccole novità nell'organizzazione e realizzazione di questa edizione, ma che non voglio svelare prima dell'evento stesso! Non resta quindi che partecipare all'evento per scoprire tutte le novità.


pgday2013_468x60_it


venerdì 13 settembre 2013

OpenERP Day

Il giorno prima del tradizionale PGDay.IT 2013, ossia il 24 ottobre, si svolgerà a Prato, presso i locali della Monash University, il primo OpenERP Day, evento volto a far crescere la community OpenERP nonché ad aumentare la diffusione di questo valido strumento software.
Sono anche convinto che, per natura e tecnologia, le due community di OpenERP e PostgreSQL (ITPUG) abbiamo molto da spartire e spero vivamente si riesca ad ottenere una solida base di partenza per future collaborazioni.



oedayit2013_468x60_it

giovedì 12 settembre 2013

room number 2403 - Matrimonio di Claudio e Martina a Monaco

Ero un po' titubante prima di affrontare questo viaggio, ma ero certo ne sarebbe valsa la pena. E poi non capita spesso di avere l'onore di poter partecipare ad un matrimonio di un caro amico emigrato!
E così assieme ad altri ex-compagni di scuola, e amici nella vita, abbiamo puntato l'auto in direzione Monaco per il matrimonio di Claudio e Martina
Il viaggio è stato tranquillo, arricchito da chiecchere su ogni argomento ci passasse per la mente. All'arrivo l'albergo prenotato per noi era veramente accogliente e moderno, e dopo poco eccoci pronti per un tuffo nel cuore di una città così affascinante.
Ci facciamo scortare da Claudio fino alla HB, nota birreria in centro, ove consumiamo una serie di tipiche pietanze tedesche, contornate da qualche litro di birra. 




Si va a letto tardi, ma il giorno seguente c'è la cerimonia.
Vestiti di tutto punto ci facciamo portare in taxi fino alla chiesa, ove siamo accolti molto calorosamente dai parenti degli sposi. Resto piacevolmente colpito dal calore e dall'affetto che aleggia nella chiesa, e mi colpiscono i parenti tedeschi che si sforzano di parlare in italiano.

Il castello ove si svolge la festa è fantastico. immenso ed elengatissimo. Le persone presenti sono tutte simpatiche e affettuose. La festa scivola via tranquilla e serena, e prima di andare a letto non ci facciamo mancare una birra.





Il giorno dopo abbiamo tempo per visitare ancora una volta il centro di Monaco, assistere all'incantevole carillon della cattedrale  e cedere alla tentazione di un nuovo pasto tedesco, sempre e rigorosamente alla HB. Dopo poco siamo nuovamente in auto verso casa.



Contenti per il nostro amico e soddosfatti del weekend.
Ne è proprio valsa la pena.

mercoledì 4 settembre 2013

Un tuffo nel passato che guardava al futuro!

Eppure la tecnologia non è arrivata a tanto!



martedì 3 settembre 2013

etags su progetti grandi

Solitamente uso etags unito ad Emacs per sfogliare il codice sorgente di progetti anche di grosse dimensioni. Tuttavia indicizzando la code base di FreeBSD mi sono trovato degli strani errori di riferimento: di fatto Emacs saltava nel punto sbagliato portandomi da un tag all'altro apparentemente senza senso.
Ho poi scoperto, grazie all'aiuto sulla mailing list Emacs, che sbagliavo l'invocazione della generazione dei tag:

cd /usr/src && find . -name '*.[ch]' -print0 | xargs -0 etags

questo comando sfrutta la capacità di xargs di lanciare piu' job in parallelo, e quindi ci si trovava ad avere dei processi etags concorrenti fra loro che sovrascrivevano le modifiche in modo conflittuale.
Siccome etags consente di leggere direttamente da standard input i file da indicizzare, il seguente comando risulta piu' lungo ma accurato nei risultati:

cd /usr/src && find . -name '*.[ch]' | etags -

lunedì 2 settembre 2013

Una frase molto importante




Questo filmato tratto da La Storia Infinita contiene una frase che mi ha sempre colpito molto e che ritengo sia ogni giorno piu' valida:

è molto piu' facile dominare chi non crede in niente

Non importa in cosa si creda, se nella pace, nella religione, nei sentimenti o perfino nel Free Software, l'importante è crederci seriamente e continuare a sperare.

martedì 27 agosto 2013

PostgreSQL fancy uptime

Dalla versione 8.1 PostgreSQL mette a disposizione una funzione interna, pg_postmaster_start_time(), che restituisce il momento di avvio dell'istanza corrente (ossia del postmaster).
Unendo tale funzione al current_timestamp e' possibile ottenere facilmente il tempo di uptime del server:

# SELECT date_trunc( 'seconds', current_timestamp - pg_postmaster_start_time() );
date_trunc
------------
00:32:37

In questo modo e' possibile ottenere l'intervallo temporale di uptime del server con precisione al secondo.

Un DBA/Sysadmin che si rispetti dovrebbe sempre controllare con precisione l'uptime del server, ma per chi vuole un uptime un po' piu' "fancy", ho creato una stored procedure, denominata appunto "uptime", che restituisce una stringa di testo con una frase descrittiva del tempo di esecuzione del server, opportunamento arrotondato.
Ad esempio:

# SELECT uptime();
uptime
--------------------
Almost 35 minutes

E ad esempio, dopo 47 minuti di attivita' la funzione di uptime riporta:

# SELECT uptime();
uptime
---------------
Almost 1 hour

La funzione opera in questo modo:
1) ottiene l'uptime in modo preciso;
2) spezza l'uptime nelle sue singole parti (giorni, ore, minute, secondi);
3) calcola gli arrotondamenti per eccesso/difetto. Ad esempio se sono passati piu' di 30 secondi si incrementa di una unita' il contatore dei minuti e si escludono i secondi; se analogamente sono passati piu' di 45 minuti si incrementa il contatore delle ore e si tralasciano i minuti, e cosi' via;
4) si decide quali "pezzi" far vedere (anni, giorni, ore, minuti);
5) si compone una stringa con opportuni separatori lessicali.

Ovviamente la funzione puo' essere migliorata, e buona parte del tempo speso dalla funzione stessa serve a calcolare cosa far vedere all'utente e con che arrotondamento. Questo a maggiore ragione colloca la funzione in ambito "fancy" e non certo come strumento di precisione per la manutenzione dell'istanza PostgreSQL.


Ci sono alcuni casi particolari: se il server e' stato avviato da meno di 10 minuti allora viene ritornato il valore speciale 'now' (da non confondere con l'equivalente testo spesso usato in PostgreSQL):

# SELECT uptime();
uptime
-------------
Almost now!

Se si cade nell'intervallo temporale di +10 e -15 minuti i minuti sono mostrati con maggiore precisione presunta, come ad esempio:

# SELECT uptime();
uptime
-------------------------
Pretty much 12 minutes

Di seguito il codice sorgente della funzione.


CREATE OR REPLACE FUNCTION uptime()
RETURNS text
AS $BODY$

DECLARE
current_uptime_interval interval;
current_description text;
current_hours float;
current_minutes float;
current_days float;
current_years float;
current_seconds float;
minutes_separator text;
hours_separator text;
days_separator text;
BEGIN

current_hours := 0;
current_minutes := 0;
current_days := 0;
current_years := 0;
current_seconds := 0;
minutes_separator := '';
days_separator := '';
hours_separator := '';
current_description := 'Pretty much ';

SELECT date_trunc( 'seconds', current_timestamp - pg_postmaster_start_time() )
INTO current_uptime_interval;

SELECT date_part( 'hour', current_uptime_interval )
INTO current_hours;

SELECT date_part( 'minutes', current_uptime_interval )
INTO current_minutes;

SELECT date_part( 'days', current_uptime_interval )
INTO current_days;

SELECT date_part( 'seconds', current_uptime_interval )
INTO current_seconds;



IF current_seconds > 30 THEN
current_seconds := 0;
current_minutes := current_minutes + 1;
current_description := 'Almost ';
END IF;

IF current_minutes >= 45 THEN
current_hours := current_hours + 1;
current_minutes := 0;
current_description := 'Almost ';
ELSEIF current_minutes <= 10 THEN current_minutes := 0; current_description := 'Almost '; END IF; IF current_hours >= 16 THEN
current_days := current_days + 1;
current_hours := 0;
current_minutes := 0;
current_description := 'Almost ';
END IF;

IF current_days >= 300 THEN
current_days := 0;
current_hours := 0;
current_minutes := 0;
current_years := current_years + 1;
current_description := 'Almost ';
END IF;


-- special case: the server started here!
IF current_years = 0
AND current_days = 0
AND current_hours = 0
AND current_minutes < 10 THEN RETURN 'Almost now!'; END IF; IF current_years > 0 AND current_days > 0 THEN
days_separator := ' and ';
END IF;
IF current_days > 0 AND current_hours > 0 THEN
hours_separator := ' and ';
END IF;
IF current_hours > 0 AND current_minutes > 0 THEN
minutes_separator := ' and ';
END IF;


SELECT current_description
|| CASE WHEN current_years = 1 THEN '1 year'
WHEN current_years > 1 THEN current_years || ' years'
ELSE ''
END
|| days_separator
|| CASE WHEN current_days = 1 THEN '1 day'
WHEN current_days > 1 THEN current_days || ' days'
ELSE ''
END
|| hours_separator
|| CASE WHEN current_hours = 1 THEN '1 hour'
WHEN current_hours > 1 THEN current_hours || ' hours'
ELSE ''
END
|| minutes_separator
|| CASE WHEN current_minutes = 1 THEN '1 minute '
WHEN current_minutes > 1 THEN current_minutes || ' minutes '
ELSE ''
END
INTO current_description;

RETURN current_description;
END;
$BODY$
LANGUAGE plpgsql;

venerdì 23 agosto 2013

Una breve (e superficiale) storia della Apple



Chi mi conosce sa che non sono un gran fan dei prodotti Apple, specialmente quelli di ultima generazione. Questo video rappresenta un veloce (e ovviamente superficiale) riassunto della storia Apple e del suo creatore.
Grande attenzione deve essere posta al minuto 5, quando si introduce la vicenda BeOS vs Next.

mercoledì 21 agosto 2013

Alcuni utilizzi di Erlang

Curiosando un po' riguardo Erlang, uno dei linguaggi che conosco solo in teoria e che prima o poi mi deciderò ad imparare,
ho scoperto che questo potente linguaggio che fa del fault-tolerance (e quindi della concorrenza) la sua forza viene usato come backend per la chat di Facebook e di Whatsapp.

martedì 20 agosto 2013

L'uso del SeqScan

Il sequential scan o scansione sequenziale e' uno dei metodo di accesso ai dati in una tabella che ogni database,
e conseguentemente PostgreSQL, fornisce. Tale metodo di accesso non e' assolutamente ottimizzato e prevede la lettura "stupida" del contenuto di una tabella in maniera sequenziale, ovvero dalla prima tupla fino all'ultima.

PostgreSQL non supporta i query hints, ovvero non consente di specificare a livello di query quale indice utilizzare per recuperare le tuple. Tuttavia PostgreSQL fornisce alcuni parametri di configurazione che possono essere configurati a livello di cluster per abilitare o disabilitare alcuni metodi di accesso. Ne consegue che per forzare l'accesso tramite indice ai dati si possono disabilitare gli altri metodi di accesso.

Questo non vale per il sequential scan: tale metodo di accesso e' da considerarsi una sorta di "ultima spiaggia" per l'accesso ai dati. Di conseguenza il sequential scan non puo' essere evitato se non c'e' altro modo di recuperare i dati.

Per meglio comprendere questo concetto si consideri una piccola tabella (ossia con poche tuple) e un indice sulla chiave primaria definita come segue:


demodb=# CREATE TABLE foo( pk SERIAL NOT NULL, description TEXT, PRIMARY KEY( pk ) );
NOTICE: CREATE TABLE will create implicit sequence "foo_pk_seq" for serial column "foo.pk"
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "foo_pkey" for table "foo"
CREATE TABLE
demodb=# INSERT INTO foo( description ) VALUES( 'Test ' || generate_series(1, 100 ) );
INSERT 0 100
demodb=# ANALYZE foo;
ANALYZE
demodb=# SELECT relname, relpages, reltuples FROM pg_class
WHERE relname = 'foo' AND relkind = 'r';

relname | relpages | reltuples
---------+----------+-----------
foo | 1 | 100
(1 row)



Come ci si puo' aspettare, essendo la relazione piuttosto piccola (solo una pagina dati), l'accesso ai dati sara' di tipo sequenziale anche in presenza di una query risolvibile tramite l'indice:


demodb=# SHOW enable_seqscan;
enable_seqscan
----------------
on
(1 row)

demodb=# EXPLAIN ANALYZE SELECT * FROM foo WHERE pk = 10;
QUERY PLAN
---------------------------------------------------------------
Seq Scan on foo (cost=0.00..2.25 rows=1 width=11)
(actual time=0.024..0.053 rows=1 loops=1)
Filter: (pk = 10)
Total runtime: 0.097 ms
(3 rows)



Essendo presente un indice, se si disabilita il sequential scan si ottiene che l'accesso ai dati viene forzatamente fatto tramite il suddetto indice:



demodb=# SET enable_seqscan TO off;
SET
demodb=# SHOW enable_seqscan;
enable_seqscan
----------------
off
(1 row)

demodb=# EXPLAIN ANALYZE SELECT * FROM foo WHERE pk = 10;
QUERY PLAN
----------------------------------------------------------------------------
Index Scan using foo_pkey on foo (cost=0.00..8.27 rows=1 width=11)
(actual time=0.031..0.034 rows=1 loops=1)
Index Cond: (pk = 10)
Total runtime: 0.086 ms
(3 rows)



Come si puo' facilmente vedere il costo dell'accesso via indice e' superiore a quello sequenziale, poiché la relazione e' troppo piccola per trarre giovamento dal caricamento delle pagine di indice.
Ma cosa succede se l'indice non e' presente? E' sufficiente ripetere l'esperimento senza creare l'indice sulla chiave primaria per verificare il comportamento:



demodb=# DROP TABLE foo;
DROP TABLE
demodb=# CREATE TABLE foo( pk SERIAL NOT NULL, description TEXT );
NOTICE: CREATE TABLE will create implicit sequence "foo_pk_seq" for serial column "foo.pk"
CREATE TABLE
demodb=# INSERT INTO foo( description ) VALUES( 'Test ' || generate_series(1, 100 ) );
INSERT 0 100
demodb=# ANALYZE foo;
ANALYZE
demodb=# SHOW enable_seqscan;
enable_seqscan
----------------
off
(1 row)

demodb=# EXPLAIN ANALYZE SELECT * FROM foo WHERE pk = 10;
QUERY PLAN
-----------------------------------------------------------------------------
Seq Scan on foo (cost=10000000000.00..10000000002.25 rows=1 width=11)
(actual time=0.025..0.054 rows=1 loops=1)
Filter: (pk = 10)
Total runtime: 0.100 ms
(3 rows)



Come si puo' notare l'accesso ai dati e' ancora di tipo sequenziale, e non potrebbe essere altrimenti visto che non vi sono altri "percorsi" per raggiungere i dati. La cosa interessante pero' e' che il costo di accesso ai dati e' notevolmente piu' grande del caso precedente, e si tratta solo di un costo presunto, visto che quello effettivo e' rimasto invariato.
L'idea e' quindi quella di aumentare notevolmente il costo presunto di accesso per invogliare l'ottimizzatore a cercare altre strade per l'accesso ai dati.
Da notare che il costo di accesso sequenziale non viene mutato, di fatto e' il query planner che incrementa il costo presunto quando trova un metodo di accesso disabilitato.