25 giugno 2007

Falcon alpha: vediamo se funziona

Installato Ubuntu server 64 bit, spacchettiamo mysql 6 alpha e configuriamo i sorgenti:
root@ubu642:~# ./configure --with-plugins=all
seguito da un make e make install. Consiglio di utilizzare --prefix=/usr/local/mysql per "inscatolare" la versione alpha di mysql in una sua directory particolare, altrimenti tutto va in /usr/local. Copiate la vostra versione preferita di my.cnf in /etc, create il database "starter" con mysql_install_db, cambiate i permessi del database con chmod, e impostate la password di root con mysqladmin; create poi un utente che ha tutti i grant sul database di test predisposto.

CREATE TABLE f (
fid int(11) NOT NULL,
descr varchar(32) DEFAULT NULL,
PRIMARY KEY (fid)
) ENGINE=Falcon;

Popoliamo la tabella:

insert into f values (1, 'uno');
insert into f values (2, 'due');
insert into f values (3, 'tre');
insert into f values (4, 'quattro');

Da un'altra sessione:

select * from f;
+-----+---------+
| fid | descr |
+-----+---------+
| 1 | uno |
| 2 | due |
| 3 | tre |
| 4 | quattro |
+-----+---------+
5 rows in set (0.00 sec)

Dalla prima sessione:

set autocommit=0;
update f set fid = 7 where fid = 4;

Dalla seconda sessione:

mysql> select * from f;
Empty set (0.00 sec)

Da qualche prova ulteriore, meno incomprensibile, è saltato fuori che bisogna committare anche la seconda sessione per vedere le modifiche della prima. Tutto questo in repeatable-read transaction isolation mode.
Ho provato anche in read-committed (la nostra preferita :-)) e non è un granché meglio.
Falcon fallisce inoltre il test di aggiornamento della chiave primaria:
update f set fid = fid+1;
dà una violazione di chiave primaria.

Bene. Aspettiamo ancora un po'. È meglio.

5 commenti:

Anonimo ha detto...

Tu scrivi:

"Falcon fallisce inoltre il test di aggiornamento della chiave primaria:
update f set fid = fid+1;
dà una violazione di chiave primaria."

ma scusa: se l'update parte con la prima chiave (fid = 1) e (dalla tua regola) mette fid=2 è chiaro che violi la condizione di chiave primaria (la seconda riga ha già fid=2)... non è giusto, quindi?

Rudy ha detto...

No: è un'operazione atomica che vuole aumentare di un'unità la chiave primaria a tutte le righe.
Lo stato del db prima della mia update e dopo la mia update (se fosse riuscita) sono compatibili tra loro; è il motore del db che opera proceduralmente, ovvero parte dalla prima riga a fare l'aggiornamento e controlla subito la chiave primaria, ma questo fa parte della particolare implementazione del db, non dell'operazione che io intendo eseguire su una relazione.
L'operazione (un'unica operazione) che effettuo o deve riuscire in blocco oppure deve fallire in blocco, ma siccome io so che lo stato finale che voglio raggiungere rispetta le regole che io ho definito per la relazione, è il db che sbaglia.
Facciamo un esempio con un noto db commerciale :-)

RUDY@hillrudy > create table emp2 as select * from scott.emp;

Table created.

RUDY@hillrudy > select empno, ename from emp2;

EMPNO ENAME
---------- ----------
7369 SMITH
7499 ALLEN
7521 WARD
7566 JONES
7654 MARTIN
7698 BLAKE
7782 CLARK
7788 SCOTT
7839 KING
7844 TURNER
7876 ADAMS
7900 JAMES
7902 FORD
7934 MILLER

14 rows selected.

RUDY@hillrudy > alter table emp2 add constraint pk_emp2 primary key (empno);
Table altered.

RUDY@hillrudy > update emp2 set empno = empno+1;
14 rows updated.

RUDY@hillrudy > commit;

Commit complete.

RUDY@hillrudy > select empno, ename from emp2;
EMPNO ENAME
---------- ----------
7370 SMITH
7500 ALLEN
7522 WARD
7567 JONES
7655 MARTIN
7699 BLAKE
7783 CLARK
7789 SCOTT
7840 KING
7845 TURNER
7877 ADAMS
7901 JAMES
7903 FORD
7935 MILLER

14 rows selected.

RUDY@hillrudy >

gmax ha detto...

Salve.
Un po' in ritardo nel commentare, ma ho visto questo blog solo oggi.

Il primo caso non da un risultato vuoto, se la prima sessione parte in autocommit=1.
Con autocommit=0 (in transaction mode) è corretto aspettarsi che la seconda sessione non veda nessun risultato SE TUTTI GLI INSERT sono stati fatti in tale modo.

Anche il secondo caso è documentato. Si può modificare la chiave primaria in modo crescente usando la clausola ORDER BY.

update f set fid = fid+1 order by fid DESC;

Rudy ha detto...

@gmax:

Forse la sequenza delle operazioni non è chiara. Prova a rileggere.

Nel primo caso l'autocommit era evidentemente a on, visto che dall'altra sessione si vedevano i dati inseriti. L'autocommit è stato impostato dopo a 0, e il risultato nella seconda sessione è eloquente! Senza fare la commit anche della seconda sessione (che è in sola lettura) non si vedono i dati inseriti già committati che un attimo prima si vedevano!

L'update con l'"order by" mi pare quantomeno folkloristica, per non dire una patch di convenienza. La documentazione dice che serve a fare in modo che le righe con id più grande vengano aggiornate prima di quelle con id più piccolo.
Questo concetto contrasta con l'atomicità di cui mysql si fregia, per non parlare dei dubbi che potrebbe far sorgere sulla effettiva concorrenza degli accessi col nuovo motore (su quello vecchio myisam non c'erano dubbi: tutti in coda).

gmax ha detto...

La sequenza delle operazioni era chiara. Usando la versione piu' recente di Falcon, non ho potuto ripetere il comportamento che hai indicato.
Probabilmente dal momento in cui hai fatto il test ad ora quel bug e' stato scoperto e riparato.

Per quanto riguarda il trucco dell'ORDER BY, non posso far altro che associarmi. Si tratta di un elemento folkloristico, non di un effetto dell'atomicita' come avviene in Oracle. Sappi solo che e' possibile raggiungere lo scopo usando questo stratagemma.

Se decidi di fare altri test e trovi altri problemi, puoi segnalare gli errori usando il servizio apposito.

Ciao
G