giovedì 28 maggio 2009

Log Collector

PostgreSQL permettere di effettuare il log delle attività del database principalmente in due modi: il primo è tramite il classico syslog, il secondo è tramite un log collector. Quest'ultimo è un processo specializzato con il quale tutti i backend comunicano, e il cui unico scopo è quello di inserire su log le informazioni ricevute. L'uso del log collector consente di avere un log molto piu' pulito e completo rispetto a quello ottenuto con syslog, anche perché il primo puo' facilmente loggare informazioni circa il mancato caricamento di un modulo (ad esempio di linguaggio) o altro.
Il log collector viene abilitato agendo sul parametro di configurazione di postgresql.conf:

logging_collector = on
(richiede il riavvio del cluster)

Da questo momento il log collector è attivo e inizierà a memorizzare i log secondo le impostazioni fornite nel file postgresql.conf. E' possibile notare la differenza nel run-time nel caso di abilitazione o meno del log collector: con il log collector attivo la lista dei processi postgresql aumenta di una unità (il collector appunto).
Qualora poi le informazioni diventino troppe, o si voglia forzare una rotazione dei file di log, è possibile da un terminare invocare la funzione pg_rotate_logfile():

select pg_rotate_logfile();

e ottenere la creazione di un nuovo file di log.

lunedì 25 maggio 2009

Amarok 2.0.2: caricare file sull'ipod

Nelle versioni 1.x di Amarok, caricare file sull'ipod (o su un lettore MP3 collegato) era banale. Bastava infatti trascinare i file dalla playlist all'elenco dei brani del lettore MP3 per accodarli, dopodiché si doveva semplicemente premere il pulsante Transfer per passarli definitivamente al lettore.
Nella versione 2.x di Amarok questa procedura non esiste piu', e occorre usare un metodo piu' semplice e immediato, ma meno intuitivo e documentato. Anzitutto occorre notare che in Amarok 2.x l'ipod (o il lettore MP3) compare come una Collection a sé. Per trasferire i file è quindi necessario andare nella sezione Files, individuare i file da trasferire, selezionarli, e fare click con il tasto destro su di essi. Si aprirà un menu' contestuale, dal quale è possibile selezionare la voce Copy To => iPod Collection. E il gioco è fatto: i file saranno immediatamente trasferiti sull'iPod.

lunedì 18 maggio 2009

Drop table e cancellazione del file su disco

Quando si esegue un drop table, PostgreSQL azzera il file fisico su disco corrispondente alla tabella specificata (pg_class.relfilenode) ma non cancella il file da disco. La ragione di ciò è nell'evitare di avere diverse possibili corse critiche, come ad esempio un riassegnamento di quel relfilenode ad un'altra tabella appena creata. In sostanza PostgreSQL tiene da parte una lista di file node disponibili per essere riciclati, e nel caso una drop table sia seguita da una create table, riutilizza il file node già allocato. In questo modo non si deve chiedere al sistema operativo di ricreare il file su disco, risparmiando tempo e risorse.
Ovviamente però potrebbe capitare che il file non sia mai piu' riciclato, ed è per questo che PostgreSQL quando giunge al prossimo checkpoint verifica la lista dei relfilenode riutilizzabili, e rimuove fisicamente da disco quelli che non stati riassegnati.

venerdì 15 maggio 2009

Vacuum

Una cosa che molto spesso lascia perplessi gli utenti che si avvicinano a PostgreSQL è l'uso di vacuum per l'analisi di una tabella e la sua "pulizia" da tuple morte. La necessità dell'utilizzo di vacuum deriva dal sistema di storage non-overwriting che PostgreSQL ha adottato fin dalle prime versioni, e che poi oggi è parte integrante del sistema MVCC. Senza dilungarsi troppo sull'argomento, l'idea è che ogni tupla modificata (ossia una tupla sottoposta a scrittura come UPDATE o DELETE) non viene aggiornata in loco, ma viene appesa in fondo alla tabella come nuova. La vecchia tupla viene poi invalidata (coerentemente con le transazioni in corso) e solo la nuova rimane (se correttamente committata). Mediante questa tecnica il database riesce ad implementare un buon isolamento fra le transazioni senza richiedere troppi lock.
Questo però richiede che ogni tanto venga reclamato lo spazio occupato da tuple morte, e questo è uno dei compiti di vacuum. Oltre a questo, vacuum si occupa di aggiornare le statistiche di sistema per poter fornire dati precisi all'ottimizzatore.
La buona notizia è che vacuum è solitamente attivo in modalità automatica in tutte le installazioni recenti, quindi non dovrete eseguirlo a mano.

Per mostrare l'uso di vacuum noi dovremo prima di tutto disabilitare l'aggiornamento automatico delle statistiche, agendo sui parametri track_count e track_activities e impostandoli ad off.
Successivamente possiamo creare una tabella di prova con cui giocare:

pgdaydb=# create table test_table(id serial, descrizione varchar);
NOTICE: CREATE TABLE will create implicit sequence "test_table_id_seq"
for serial column "test_table.id"
CREATE TABLE
pgdaydb=# insert into test_table(descrizione) values('Prima riga');
INSERT 0 1
pgdaydb=# insert into test_table(descrizione) values('Seconda riga');
INSERT 0 1
pgdaydb=# insert into test_table(descrizione) values('Terza riga');
INSERT 0 1
pgdaydb=# insert into test_table(descrizione) values('Quarta riga');
INSERT 0 1

Se ora chiediamo le statistiche sulla tabella otteniamo che la tabella risulta essere ancora vuota (ossia per il sistema non ci sono tuple inserite):

pgdaydb=# select relname, reltype, relfilenode, relpages, reltuples
from pg_class where relname = 'test_table';
relname | reltype | relfilenode | relpages | reltuples
------------+---------+-------------+----------+-----------
test_table | 26147 | 26145 | 0 | 0

Se guardiamo su disco la dimensione del file corrispondente alla tabella, troviamo che esso occupa 8 KB, ossia lo spazio di esattamente una pagina (le quattro tuple infatti sono abbastanza piccole per ricadere in una pagina dati). Ricordiamoci infatti che le tabelle sono organizzate a pagine di 8KB, e quindi il sistema alloca sempre multipli di 8KB:

ls -lh 26145
-rw------- 1 postgres postgres 8.0K 2009-05-15 08:08 26145
Ora possiamo popolare la nostra tabella forzando delle insert fino ad arrivare a circa 2 milioni di record; è sufficiente ripetere qualche volta la query seguente:

INSERT INTO test_table(descrizione) SELECT descrizione FROM test_table;
A questo punto lo spazio disco occupato dalla tabella è notevolmente cresciuto:

ls -lh 26145
-rw------- 1 postgres postgres 93M 2009-05-15 08:12 26145
Siccome le statistiche non vengono aggiornate in automatico, il sistema è ancora convinto che non vi siano tuple nella tabella, e quindi una eventuale query porterebbe a percorsi sbagliati (ossia uno scan sequenziale quando magari un indice sarebbe piu' opportuno):

select relname, reltype, relfilenode, relpages, reltuples
from pg_class where relname = 'test_table';
relname | reltype | relfilenode | relpages | reltuples
------------+---------+-------------+----------+-----------
test_table | 26147 | 26145 | 0 | 0


Cosa succede se ora facciamo un update di tutte le tuple? Vengono generate 2 milioni di nuove tuple che invalidano le precedenti, e infatti lo spazio disco occupato dalla tabella cresce di circa il doppio:

pgdaydb=# update test_table set descrizione='Nuova descrizione';
UPDATE 2097152

ls -lh 26145
-rw------- 1 postgres postgres 197M 2009-05-15 08:14 26145

Chiediamo a vacuum di aggiornare le statistiche di sistema:

pgdaydb=# vacuum analyze test_table;
VACUUM
pgdaydb=# select relname, reltype, relfilenode, relpages, reltuples
from pg_class where relname = 'test_table';
relname | reltype | relfilenode | relpages | reltuples
------------+---------+-------------+----------+-------------
test_table | 26147 | 26145 | 25206 | 2.09715e+06


ls -lh 26145
-rw------- 1 postgres postgres 197M 2009-05-15 08:14 26145
Quello che succede è che vacuum scorre la tabella per vedere quante pagine dati sono presenti, quante tuple sono valide nelle pagine dati e aggiorna le statistiche di sistema. Notare che le tuple valide sono effettivamente 2 milioni e che le pagine sono 25206, che forniscono uno spazio disco di circa 200 MB, come infatti risulta guardando lo spazio occupato su disco.

Siccome sappiamo che la tabella contiene 4 milioni di tuple, di cui solo 2 milioni sono valide, possiamo richiedere il vacuum della tabella e ottenere la riduzione di spazio.


pgdaydb=# vacuum full verbose test_table;
INFO: vacuuming "public.test_table"
INFO: "test_table": found 0 removable, 2097152 nonremovable row versions in 25206 pages
DETAIL: 0 dead row versions cannot be removed yet.
Nonremovable row versions range from 46 to 46 bytes long.
There were 2097152 unused item pointers.
Total free space (including removable row versions) is 88442096 bytes.
11848 pages are or will become empty, including 0 at the end of the table.
11850 pages containing 88388672 free bytes are potential move destinations.
CPU 0.06s/0.22u sec elapsed 0.28 sec.
INFO: "test_table": moved 1836489 row versions, truncated 25206 to 13509 pages
DETAIL: CPU 0.95s/4.95u sec elapsed 18.32 sec.
INFO: vacuuming "pg_toast.pg_toast_26145"
INFO: "pg_toast_26145": found 0 removable, 0 nonremovable row versions in 0 pages
DETAIL: 0 dead row versions cannot be removed yet.
Nonremovable row versions range from 0 to 0 bytes long.
There were 0 unused item pointers.
Total free space (including removable row versions) is 0 bytes.
0 pages are or will become empty, including 0 at the end of the table.
0 pages containing 0 free bytes are potential move destinations.
CPU 0.00s/0.00u sec elapsed 0.00 sec.
INFO: index "pg_toast_26145_index" now contains 0 row versions in 1 pages
DETAIL: 0 index pages have been deleted, 0 are currently reusable.
CPU 0.00s/0.00u sec elapsed 0.00 sec.
VACUUM
Notate che il sistema analizza la tabella, decide di troncare le pagine dati muovendo le tuple e compattando lo spazio (truncated 25206 to 13509 page) e infatti, osservando lo spazio disco si ha che questo si è quasi dimezzato:

ls -lh 26145
-rw------- 1 postgres postgres 106M 2009-05-15 08:16 26145

Cosa si conclude da tutto ciò?
Vacuum è uno strumento indispensabile, consente sia di aggiornare le statistiche di sistema (indispensabili per l'ottimizzatore) che di ricompattare lo spazio non usato. Comprendere la sua necessità, dovuta anche all'esistenza del sistema di storage non overwriting e a MVCC è la base per ogni DBA PostgreSQL.
Ma come è già stato scritto, il sistema attiva l'autovacuum per default e anche le statistiche vengono solitamente aggiornate automaticamente, quindi ci sono buone probabilità che non dobbiate mai intervenire manualmente!

mercoledì 13 maggio 2009

Gestione dei tipi nel driver JDBC

Immagiamo di avere una tabella con un campo data, uno intero e uno stringa, e di scrivere e usare il seguente semplice programma JDBC:

public class PGTest {
public static void main(String[] args) throws Exception{
Class driverClass = Class.forName("org.postgresql.Driver");
driverClass.newInstance();

Connection connection = DriverManager.getConnection("jdbc:postgresql://localhost/pgdaydb","luca", "fluca");

Statement st = connection.createStatement();
String sql = "SELECT date_field, int_field, string_field FROM mytable";
ResultSet rs = st.executeQuery(sql);

while(rs.next()){
String stringForDate = rs.getString("date_field");
String stringForInt = rs.getString("int_field");
int intForString = rs.getInt("string_field");

System.out.println("Obtained: " + stringForDate + " - " + stringForInt + " - " + intForString);
}

}
}

Quello che succede è che i campi sono ottenuti dal database, ma i loro valori sono scambiati: il tipo data e intero sono inseriti in stringhe e quello stringa in un intero.
Se siete fortunati, questo programma girerà senza nessun problema!
Come mai avviene cio?
La ragione è che il driver JDBC di PostgreSQL gestisce la comunicazione con il backend attraverso stringhe di caratteri, e quindi ogni valore di tupla inviato indietro dal database è restituito come "stringa". A questo punto, quando su una colonna invocate un getInt() il driver effettua (si veda AbstractJdbc2ResultSet):

 public int getInt(int columnIndex) throws SQLException
{
checkResultSet(columnIndex);
if (wasNullFlag)
return 0; // SQL NULL

Encoding encoding = connection.getEncoding();
if (encoding.hasAsciiNumbers()) {
try {
return getFastInt(columnIndex);
} catch (NumberFormatException ex) {
}
}
return toInt( getFixedString(columnIndex) );
}



public static int toInt(String s) throws SQLException
{
if (s != null)
{
try
{
s = s.trim();
return Integer.parseInt(s);
}
catch (NumberFormatException e)
{
try
{
BigDecimal n = new BigDecimal(s);
BigInteger i = n.toBigInteger();

int gt = i.compareTo(INTMAX);
int lt = i.compareTo(INTMIN);

if (gt > 0 || lt < 0)
{
throw new PSQLException(GT.tr("Bad value for type {0} : {1}", new Object[]{"int",s}),
PSQLState.NUMERIC_VALUE_OUT_OF_RANGE);
}
return i.intValue();

}
catch ( NumberFormatException ne )
{
throw new PSQLException(GT.tr("Bad value for type {0} : {1}", new Object[]{"int",s}),
PSQLState.NUMERIC_VALUE_OUT_OF_RANGE);
}
}
}
return 0; // SQL NULL
}


Quindi il driver effettua una semplice conversione a Integer della stringa con il valore della colonna. In sostanza il driver non effettua nessun controllo sul tipo del dato che si sta chiedendo al ResultSet, e tenta di convertirlo da stringa al valore desiderato.
Si noti che comunque il driver e' ingrado di stabilire il tipo di una determinata colonna, e in effetti la generica getObject() viene implementata per mezzo di getInternalObject():

 protected Object internalGetObject(int columnIndex, Field field) throws SQLException
{
switch (getSQLType(columnIndex))
{
case Types.BIT:
// Also Types.BOOLEAN in JDBC3
return getBoolean(columnIndex) ? Boolean.TRUE : Boolean.FALSE;
case Types.TINYINT:
case Types.SMALLINT:
case Types.INTEGER:
return new Integer(getInt(columnIndex));
case Types.BIGINT:
return new Long(getLong(columnIndex));
case Types.NUMERIC:
case Types.DECIMAL:
return getBigDecimal
(columnIndex, (field.getMod() == -1) ? -1 : ((field.getMod() - 4) & 0xffff));
case Types.REAL:
return new Float(getFloat(columnIndex));
case Types.FLOAT:
case Types.DOUBLE:
return new Double(getDouble(columnIndex));
case Types.CHAR:
case Types.VARCHAR:
case Types.LONGVARCHAR:
return getString(columnIndex);
case Types.DATE:
return getDate(columnIndex);
case Types.TIME:
return getTime(columnIndex);
case Types.TIMESTAMP:
return getTimestamp(columnIndex, null);
case Types.BINARY:
case Types.VARBINARY:
case Types.LONGVARBINARY:
return getBytes(columnIndex);
case Types.ARRAY:
return getArray(columnIndex);
case Types.CLOB:
return getClob(columnIndex);
case Types.BLOB:
return getBlob(columnIndex);
...
}
e quindi viene cercato il tipo della colonna per poter fare un cast automatico opportuno.
Nelle specifiche JDBC esiste una tabella che illustra le conversioni che un driver deve supportare fra i vari tipi. Ad esempio la tabella illustra come una data possa anche essere ottenuta come byte[]. Si presti attenzione al fatto che tali conversioni sono le minime indispensabili che un driver deve fornire, quindi il fatto che il driver JDBC di PostgreSQL consenta anche la conversione di esempio da data a stringa non rappresenta affatto una limitazione del driver stesso.

martedì 12 maggio 2009

Costruire una corda

In questo articolo illustro il mio modo di realizzare corde per archi. E' possibile che siate in disaccordo con alcune o tutte le cose che scriverò di seguito, ma questo è il mio modo di realizzare corde, dovuto ad un insieme di tecniche che io e mio padre abbiamo appreso e messo a punto negli anni. I risultati sono piu' che soddisfacenti, e infatti non ho mai avuto problemi tecnici alle corde così realizzate (se non la normale usura dei serving).
La motivazione dietro questo articolo è anche quella di fornire un aiuto a chi si appresta a cominciare la costruzione delle corde, visto che in rete non sempre si trovano buone descrizioni del processo realizzativo.
Da notare che le foto mostrate qui si riferiscono ad una corda di "test", quindi realizzata bene ma senza una cura maniacale; di conseguenza non fissatevi troppo sul risultato finale che vedrete ma sulla descrizione del procedimento, che puo' portarvi a risultati eccellenti.

Cose indispensabili
  • il telaio per corde: senza questo è impossibile procedere. Il telaio deve avere una struttura telescopica, in modo da poter essere regolato alla lunghezza che la corda deve assumere. Inoltre deve essere dotato di due bracci a U capaci di rotare sul centro del telaio stesso. Ciascuna estremità dei bracci deve avere una carrucolina o un sostegno circolare attorno al quale verranno avvolti i fili della corda.
  • i filati: occorre avere il rocchetto del filato principale (quello con il quale sarà realizzata la corda) e almeno un rocchetto di filato per serving. Io generalmente faccio i loop con del fast-flight, perché morbido e flessibile, mentre uso del nylon per il serving centrale (quello dell'incocco) poiché piu' uniforme, liscio e meno soggetto a usura rispetto al fast-flight. Lo svantaggio del nylon è che tende a rompersi facilmente, sia in fase di costruzione della corda che durante il normale utilizzo. Se siete dotati di pazienza e siete disposti a rischiare di dover rifare il serving allora il nylon vi darà maggiori soddisfazioni, altrimenti procedete con il fast-flight che però con il tempo tenderà ad assotigliarsi in particolare nel punto dell'incocco. Per la corda io uso indistintamente fast-flight o dyneema. L'ultimo è il migliore, poiché consente di ottenere corde piu' morbide e robuste, ed inoltre non è cerato come il primo e quindi consente mediamente di usare due fili in piu' per corda. Potete anche usare un singolo filato sia per la corda che per i serving, anche se questa non è una soluzione molto in voga.
  • tempo: fare una corda richiede tempo e pazienza. Non iniziate a fare una corda se avete poco tempo o non siete nella condizione giusta per farlo.
  • cutter: dovrete tagliare velocemente e in modo abbastanza preciso pezzi di filato, quindi meglio usare un cutter che un paio di forbici.
  • accendino o fiammiferi: per bruciare le estremità dei fili.
  • una buona illuminazione: l'ideale è di avere una lampada da ufficio (a pantografo) per poter illuminare la zona in cui state lavorando.
  • una freccia: per testare la presa della cocca sul serving centrale.
Cose opzionali (ma utili)
  • un paio di pinze (sottili): siccome dovrete tendere con forza i fili, rischiate di rovinarvi le mani nell'operazione, e quindi un paio di pinze possono risolvervi il problema.
  • un paio di morsetti: necessari per fissare il telaio al tavolo, così da poter tenderlo senza rischiare che si muova.
  • un paio di piastine sottili metalliche: da usare per impedire alla corda di avvolgersi troppo su se stessa mentre create il serving.
  • un pennarello: utile per marcare sulla corda le posizioni in cui iniziare e finire i serving.
  • un righello: utile per misurare la lunghezza dei serving in realizzazione.

Concetti preliminari

La corda è dotata di due anelle che si infilano nei tip dei flettenti, una piccola (inferiore) e una piu' grande (superiore). Le anelle possono essere fatte principalmente in due modi:
  1. con un unico filo. In questo modo il filo che realizza il loop è lo stesso che realizza il serving che appoggerà sul flettente. Questa soluzione è semplice ed è quella che si trova nelle corde in commercio, tuttavia ha lo svantaggio di rendere il sistema loop-serving meno flessibile e meno robusto (tutto dipende da un filo solo).
  2. con due fili. In questo modo si realizza il loop in modo separato dal serving che appoggerà sul flettente. Questa è la soluzione che preferisco poiché il sistema loop-serving divente molto flessibile (e quindi si adatta meglio alla conformazione del flettente) e inoltre è piu' resistente (essendoci due fili la rottura di uno vi permetterà di usare la corda per finire la grara!).
Circa il metodo 2, che è quello che descriverò, vi sono poi diverse scuole di pensiero. Alcuni realizzano il loop con un serving fatto a mano, a maglie grosse, molto morbido e flessibile, altri invece con un serving fatto a macchina (io ad esempio), sicuramente piu' rigido ma anche piu' resistente all'usura e alle intemperie. Ricordatevi infatti che sotto al loop c'è la corda, che va comunque protetta, e un loop a maglie grosse farà penetrare nel filato della corda gli agenti atmosferici. Inoltre c'è chi sostiene che il loop e il serving normale debbano sovrapporsi e chi dice che debbano solo coincidere nella congiunzione. Personalmente realizzo corde con entrambi i metodi: se voglio una corda molto robusta (tipicamente da allenamento) sovrappongo i serving, mentre per le corde da gara uso la continuità dei due serving. Mentre nel primo caso si ha un nodo piu' grosso e rozzo, nel secondo caso si ha una corda molto piatta.

Costruzione della corda

Vediamo ora i passi necessari per la realizzazione della corda.

  • Fissaggio del telaio al tavolo.

  • Apertura del telaio alla lunghezza opportuna. Occorre aprire il telaio con i due bracci rotanti paralleli alla struttura telescopica e misurare l'apertura massima (cioè la distanza fra le due parti esterne dei bracci) che corrisponderà alla lunghezza della corda finale. Solitamente si parte, come indicazione, da una corda usata in precedenza, aprendo il telaio pari alla lunghezza di tale corda (o in piu' o in meno a seconda della lunghezza finale che si vuole ottenere). Tenete presente che i fattori che incidono sulla lunghezza finale della corda sono: tipo di filato e sua elasticità, numero di fili della corda (piu' fili ha una corda e piu' si accorcierà dandogli dei "giri"), tensione dei fili sul telaio (se i fili sono ben tesi la corda avrà esattamente quella lunghezza, senza troppe sorprese).
  • Apertura dei bracci rotanti. Occorre posizionare i due bracci ad angolo retto rispetto alla struttura principale del telaio. Verificate che la struttura telescopica del telaio sia ben fissata, in modo che il telaio non possa accorciarsi o comunque variare la sua lunghezza durante la costruzione della corda. Infine verificate che i bracci rotanti siano ben fissati in posizione trasversale al telaio e siano il piu' possibile paralleli fra loro (il telaio dovrebbe essere un rettangolo, o quantomeno un parallelogramma per non falsare la lunghezza della corda).
  • Fissate un capo del filo ad uno dei due bracci (nel mio telaio ho delle rondelle di fissaggio studiate appositamente allo scopo) e iniziate a posizionare i fili attorno ai quattro vertici dei bracci del telaio. Fate attenzione a che i fili non si sovrappongano fra loro ma restino il piu' possibile paralleli fra loro. Se i fili si accavallano la tensione fra gli stessi e la loro lunghezza potrebbe non essere uniforme. Abbiate cura di tirare i fili mentre li srotolate, in modo da assicurarvi che siano a tensione uniforme. Non tendeteli all'esasperazione, il telaio non deve diventare un violino, ma i fili non devono nemmeno essere poco tesi. Tenete presente che il numero di fili totali della corda corrisponderà al doppio dei fili visibili su ciascun lato lungo del telaio. Una volta srotolati tutti i fili chiudete il capo finale sul braccio opposto a quello da cui siete partiti (questo significa che sul lato corto orizzontale di quel braccio ci saranno lo stesso numero di fili che sugli altri lati).
  • Sbloccate i bracci rotanti e ruotateli, assicuratevi che tutti i fili abbiano la stessa tensione, e se necessario regolate la lunghezza del telaio. Rifissate poi il telaio e i bracci nella posizione di prima.
  • Si parte ora a fare il loop dell'anello piccolo (inferiore). Siccome l'anello piccolo è fisso sui flettenti (ovvero non scorre sul flettente per permettere l'allogiamento della corda), risulta anche quello meno sollecitato ad aperture e quindi intrinsicamente piu' resistente. E' quindi una buona idea costruire l'anello piccolo attorno ai bracci di apertura/chiusura della corda, così che esso "schermi" i due capi del filato. L'anello piccolo risulta quello piu' complesso da fare, proprio perché deve "chiudere" la corda e i due lembi fissati al braccio rotante (che potrebbero avere tensione diversa rispetto agli altri, come si vede dalle foto). Per prima cosa occorre stabilire la dimensione del loop; io solitamente utilizzo 8 cm di lunghezza (quindi un'anella di 4 cm di raggio). Marcate con un pennarello il centro della corda fra i due bracci (lato orizzontale corto) e da questi segnate il raggio dell'anella. Tenete presente che questo, essendo il primo anello, non richiede particolare simmetria nella sua realizzazione.
  • Inserite delle lamelle di metalle agli angoli retti della corda, in modo da evitare che i fili, durante la costruzione dei serving, si attorciglino fra di loro mutando anche la lunghezza della corda finale.
  • Per realizzare l'anello occorre anzitutto fissare il serving all'estremità di un braccio (ad esempio ad una carrucolina o una vite in esso), tirarlo in direzione parallela a quella dei fili della corda (in modo che faccia parte dei fili sul lato corto, e fare un anello (magari attorno ad un cacciavite o un punteruolo) e ripercorre in parallelo nel verso opposto. A questo punto fate un giro attorno al punto di partenza del serving e iniziate ad avvolgere il serving a mano. Il risultato dovrebbe essere di avere il serving che si avvolge attorno ai fili della corda e quello fissato al braccio mobile.
  • Dopo aver fatto un numero sufficiente di giri a mano (5-6 almeno) , continuate ad avvolgere il serving usando la macchinetta. Regolate la tensione in modo che il serving sia ben stretto (questo punto contiene i capi morti della corda e non si deve aprire). Dopo un numero di giri di circa 15-20 siete pronti per fissare il primo "nodo" del serving. Non esagerate troppo con il numero dei giri, altrimenti non riuscirete piu' a "tirare" i fili attraverso il serving. Tenendo il punteruolo attorno al quale avete fatto l'anello del serving in una mano, tirate con l'altra (eventualmente con le pinze) il capo parallelo del serving. Mettete il capo in tensione e rilasciate di colpo il punteruolo, in modo che si crei un nodo naturale alla prima estramità del serving. Tirate ancora un po' per sicurezza il capo parallelo del serving, ma non forzate troppo o rischiate che i giri del serving si sovrappongano per la troppa pressione.


  • Continuate ad avvolgere il serving con la macchinetta. Regolate la macchinetta in modo che il serving sia ben stretto ma non troppo. L'idea è che la macchinetta, lasciata libera, non dovrebbe allentare il filo (troppo morbida) né roteare in senso opposto (troppo rigida).
  • Arrivati vicini all'estremità finale del loop allentate la macchinetta, srotolate del filo e fate una grossa U attorno alla corda. L'importante è che il filo del serving e quello di incrocio della U siano opposti (se uno è sopra la corda l'altro deve essere sotto e viceversa). Fate una serie di giri a mano (non importa che siano chiusi fra loro e siano tesi) in senso opposto (cioè verso il serving) passando con la macchinetta all'interno della U. Anche qui occorrono almeno 15 giri per la chiusura. Al termine annodate la macchinetta in modo che il filo sia parallelo alla corda e in direzione del serving.
  • Svolgete i fili a mano attorno al serving. Fate ruotare la U costruendo altri giri del serving e rimovuendo quelli fatti a mano al passo precedente. All'ultimo giro avrete un solo anello che si potrà chiudere tirando il filo fissato prima all'altra estremità (verso l'inizio del loop). Potete nuovamente aiutarvi con un cacciavite sottile o un punteruolo.
  • A questo punto il loop è finito, potete tagliare il filo del serving (se intendete procedere con lo stesso filo per il serving dei flettenti allora lasciatelo intatto) e bruciare leggermente le estremità che sbucano dal serving. Non esagerate con la fiamma o la lama per non danneggiare i giri del serving.
  • Liberate le estremità della corda ancorate alle estremità del braccio. Non tagliatele ancora, possiamo infilarle sotto al serving dei flettenti per avere maggiore resistenza della corda.
  • Ruotate il braccio in modo da renderlo parallelo al telaio. Muovete la corda fino a che il serving del loop è simmetrico attorno alla carrucolina del braccio.

  • A questo punto si puo' iniziare a costruire il serving per il flettente. Si hanno due scelte possibili, come già anticipato prima: sovrapporre il serving del flettente a quello del loop o farlo immediatamente adiacente. La prima soluzione da maggiore robustezza alla corda, mentre la seconda produce una corda piu' flessibile e che meglio si adatta alla conformazione della punta del flettente. In entrambi i casi occorre anzitutto fissare un capo del filo del serving al telaio, in direzione opposta a quella del loop appena fatto. Successivamente si fa un anello che sovrasta il loop appena completato, lo si fissa con un punteruolo e si riprocede in direzione opposta al loop. Infine si inizia ad arrotolare il serving attorno alla corda nella posizione di inizio desiderata. Come prima, iniziate con dei giri a mano ben tesi, in modo da unire le due estremità della corda. Dopo qualche giro a mano proseguite con la macchinetta per una quindicina di giri circa.

  • Una volta finiti i giri di "blocco" della parte iniziale del serving possiamo procedere a tirare l'anello creato prima. Ancora una volta iniziate a tendere con decisione l'estremità del filo lasciato libero prima (quello in direzione opposta al loop) e rimuovete il punteruolo che teneva il loop velocemente . Il risultato sarà quello di chiudere la parte iniziale del serving.

  • Si procede a fare il serving con la macchinetta, avendo cura che il filo sia ben teso senza però esagerare (pena la rottura del filo stesso). Misurate il serving con un righello per assicurarvi che sia della misura desiderata. Quando siete vicini alla fine del serving procedete alla costruzione di un anello inverso come spiegato per la fase finale del primo loop. Ricordate che è importante che i giri inversi inizino dal lato verticale opposto rispetto a dove si ferma il filo del serving. Fate circa 15 giri inversi, fissate la macchinetta del serving (e il filo) in direzione del primo loop, svolgete i giri inversi e chiudete il serving tirando il capo di filo libero e usando un punteruolo per gestire l'anello di chiusura.

  • E' ora il momento di creare il loop dell'altra estremità, quello piu' grande. In questo caso è importante la geometria, ovvero il loop deve essere il piu' centrato possibile rispetto alla corda, poiché non si potrà "aggiustare" la posizione del loop come si è fatto per il precedente. Ancora una volta si parte fissando delle linguette metalliche agli angoli della corda, si marca con un pennarello la dimensione del serving, si fissa un capo del serving al telaio, si crea un anello in direzione opposta e si inizia ad avvolgere a mano il serving.

  • La costruzione del serving prosegue usando la macchinetta, e come per il loop precedente il serving viene chiuso con i giri inversi. A questo punto è possibile tagliare il filo del serving, bruciarne le estremità, girare il braccio rotante del telaio e prepararsi per la realizzazione del serving per i flettenti.

  • Il serving del flettente si realizza nello stesso modo del caso precedente. Una volta terminato è possibile unire i due tronconi della corda.

  • E' ora il momento di realizzare il serving centrale. Per prima cosa occorre marcare sulla corda l'inizio e la fine del serving stesso, per questo meglio usare una vecchia corda come riferimento. Vi consiglio di partire a fare il serving dalla parte inferiore, poiché in essa è facile fare un nodo di chiusura grosso che, se portato nella parte superiore, potrebbe graffiarvi il mento al rilascio. Per il serving è meglio usare del filo di nylon, ma fate attenzione a non tendere troppo la macchinetta o lo romperete. Al solito l'inizio del serving si ha con la costruzione di un anello: fissate un capo del filo verso l'anello superiore della corda, create l'anello e iniziate ad avvolgere a mano verso l'anello superiore. Dopo circa 15 giri tirate l'anello creato e chiudete così il serving. Procedete poi con la macchinetta per la costruzione del resto del serving. In prossimità del punto di incocco testate con una freccia la tenuta del serving. La cocca deve incastrarsi bene nel serving, e deve teoricamente cadere dalla corda se questa viene picchiettata dolcemente. Tenete presente che il nylon non si assottiglia con l'usura, quindi non fate un serving troppo grosso pensando che poi si adatti. La parte finale del serving viene chiusa con i soliti giri inversi. Una volta ultimato il serving tagliate le estremità del filo e bruciatele per farle "assorbire" nella corda.

Possibili varianti
  • L'anello piccolo (il primo realizzato) può essere ottenuto piu' facilmente se i capi della corda sono fissati in modo orizzontale (come mostrato in figura). In questo modo si spreca piu' corda ma si ha meno tensione nei fili al momento della chiusura del serving del loop.
  • E' possibile realizzare anelli "invisibili" usando del filo dello stesso colore della corda. Io ad esempio li realizzo con del fast-flight non cerato, molto resistente e allo stesso tempo morbido.

Aggiustamento della lunghezza della corda

La corda appena creata subirà un aggiustamento della sua lunghezza man mano che la usate. Tipicamente dopo una sessione di tiro la corda si è aggiustata e puo' essere considerata definitiva. La ragione di questo aggiustamento è che il telaio, per quanto teso possa essere, non solleciterà mai la corda come l'arco. I fili e i nodi verranno infatti tesi e sollecitati ad ogni tiro, fino a quando troveranno la loro collocazione stabile.
L'aggiustamento della corda sarà tanto maggiore quanto maggiore è il libraggio dell'arco e inferiore il numero di fili della corda. Ovviamente la tensione del telaio e dei fili puo' aiutare ad ottenere un setup iniziale piu' stabile.
Un metodo per ottenere una corda stabile prima di una sessione di tiro consiste in:
  1. armare l'arco con la corda appena costruita;
  2. scaldare la corda sfregandola velocemente con un panno o con un cordino avvolto ad essa;
  3. fare qualche rilascio a vuoto (ovviamente con allunghi corti);
  4. ripetere un paio di volte il procedimento.
In questo modo la corda viene sollecitata e dovrebbe adattarsi (come lunghezza) a quella definitiva.

lunedì 11 maggio 2009

Creare un operatore

Una delle maggiori differenze fra PostgreSQL e gli altri DBMS è il suo uso profondo del catalogo di sistema. In PostgreSQL infatti ogni cosa è definita nel catalogo, e quindi non solo le tabelle e le funzioni, ma anche gli operatori e gli indici trovano spazio di personalizzazione alterando il catalogo di sistema.
Questo consente, ad esempio, di creare facilmente degli operatori nuovi per agire sui dati.

Come esempio, si supponga di voler creare un operatore -% che effettua uno sconto percentuale su un valore numerico. Il primo passo da fare è quello di definire una funzione (stored procedure) che operi sui dati corretti e produca il risultato. Siccome si vuole arrivare a scrivere una cosa del tipo:

select a -% b;


l'operatore avrà due operandi, interi, e di conseguenza anche la funzione avrà gli stessi operandi (parametri). Per semplicità si supponga che il valore risultante sia intero. E' quindi possibile definire la funzione come segue:

CREATE OR REPLACE FUNCTION sconto( prezzo_lordo integer, sconto integer ) RETURNS INTEGER
AS
$BODY$
DECLARE

BEGIN
IF sconto > 0 THEN
RETURN (prezzo_lordo - (prezzo_lordo * sconto / 100) );
ELSE
RETURN prezzo_lordo;
END IF;

END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE;

A questo punto si puo' inserire il nuovo operatore, specificando il suo nome (-%), il tipo dei suoi operandi e la funzione da usare per il calcolo:

CREATE OPERATOR -% (
PROCEDURE = sconto
, LEFTARG = integer
, RIGHTARG = integer
)

E da ultimo si puo' verificare come l'operatore appena creato lavori correttamente:

select 100 -% 10 as prezzo_netto;

che riporterà in uscita 90, ovvero l'applicazione dello sconto.

PostgreSQL @ UniPI - Polo Fibonacci

Venerdì 8 Maggio mi sono recato, assieme ad altri volontari di ITPug, al Polo Fibonacci dell'Università di Pisa per un seminario su PostgreSQL.
Io e gli altri ci siamo avvicendati nella presentazione di ITPug e di PostgreSQL, passando dai concetti base (cos'è PostgreSQL e come funziona) fino alle caratteristiche interne (transazioni, log, PITR, ecc.) terminando con una panoramica sulle connessioni da diversi linguaggi esterni (Java, Perl, PHP).
E' stato molto interessante come seminario perché ha presentato tutte le nuove funzionalità del database, comprese quelle in uscita nella futura versione 8.4.
Il seminario in se ha avuto un buon successo, e infatti il pubblico si è dimostrato molto interessato e ha partecipato attivamente a tutte le discussioni che si sono alternate nelle quasi 4 ore di partecipazione.
Un'esperienza molto bella e molto interessante!