Mysql Workbench su Ubuntu 20.04

Mysql Workbench su Ubuntu 20.04
Mysql Workbench su Ubuntu 20.04

Ho reinstallato Mysql Workbench versione Community, un tool per l’amministrazione e la gestione di database basati su DBMS MySQL/MariaDB, su Ubuntu 20.04.

Al tentativo di creare una nuova connessione mi sono ritrovato un errore mai comparso prima:

An AppArmor policy prevents this sender from sending this message to this recipient; type="method_call", sender=":1.125"

eccetera.

Il problema (spiegato qui) è che ho dovuto installare MySQL con snap anziché apt, per cui mi sono scontrato con il fatto che i pacchetti installati con snap sono sandboxed, in qualche modo isolati e non possono fare alcune richieste al sistema. Ho dovuto quindi applicare questo comando:

$ sudo snap connect mysql-workbench-community:password-manager-service :password-manager-service

Ora funziona:

Sul modulo kernel Linux Apparmor ho già dedicato questo articolo.

Se vi è servito, lasciatemi un like

Matematica: la congettura di Collatz

Congettura di Collatz
Congettura di Collatz

Congettura

Cos’è una congettura? È una proposizione che si presume vera ma non si è in grado di dimostrare rigorosamente. Le congetture affascinano perché funzionano per tutti i tentativi che si fanno per verificarla, cioè per trovare una dimostrazione di ciò che dicono. E questa loro non dimostrabilità le avvolge di mistero. Facciamo un piccolo recap.

Assiomi o postulati

Sono delle affermazioni così elementari che non possono essere dedotte da affermazioni ancora più semplici. A volte non sembrano molto elementari però si decide di arrestare il processo deduttivo perché non porterebbe più da nessuna parte se non girare il discorso utilizzando dei sinonimi. Ad esempio Assioma I della geometria euclidea:

Tra due punti qualsiasi è possibile tracciare una e una sola retta.

Qui si potrebbe obiettare “cos’è la retta? cos’è un punto? Il mio professore di Analisi I, Ezio Stagnaro, ci fece questo esempio:

Potete sostituire alla parola “punto” la parola “scarpe” e alla parola “retta” la parola “uomo” e verificare se detto così l’assioma funziona. Se poi riuscite a far funzionare l’analogia per tutti gli altri assiomi, vi accorgerete che punti e rette non sono oggetti in sé ma possono essere istanziati nella realtà in qualunque modo questo consenta di non pervenire a contraddizioni.

Proposizioni e teoremi

A partire dai fatti elementari (assiomi) costruiamo affermazioni più complesse (“La somma degli angoli interni di un triangolo è congruente con un angolo piatto” per rimanere nella Geometria Euclidea) che fanno discedere un fatto complesso (tesi) ad un certo numero finito di premesse (ipotesi). Il processo deduttivo che porta dalle ipotesi alla tesi senza saltare passaggi è detto dimostrazione del teorema. Se un teorema ha una dimostrazione l’affermazione è vera all’interno del sistema assiomatico e non può essere negata.

… e le congetture?

Se non riusciamo a trovare la dimostrazione siamo in una terra di mezzo. La proposizione è verificata in un numero più o meno grande di casi, sembra tenere, ma siccome non si possono provare tutti gli infiniti casi, non possiamo essere certi che funzioni sempre. Questa sicurezza ce la può dare solo una dimostrazione rigorosa.

Gli attacchi che i matematici sferrano verso queste proposizioni “maledette” a volte hanno qualcosa di epico, perché sono in grado di resistere per secoli all’assalto di menti sopraffine.

Per citarne un’altra di celebre, oltre a quella di Collatz, basti la congettura di Riemann, secondo la quale gli zeri non banali della funzione Zeta di Riemann hanno tutti parte reale uguale a 1/2. Anche di questa non si è ancora trovata una dimostrazione, benché fosse uno dei problemi inseriti da David Hilbert nell’elenco dei 23 problemi ancora da risolvere alla fine del XIX secolo (il problema numero 8, per la precisione).

Non è nemmeno provato che queste proposizioni non si possono dimostrare, almeno ci si metterebbe l’anima in pace. La proverbiale “pietra sopra” ad esempio è stata messa in un caso famoso: dopo secoli di tentativi da parte di matematici più o meno bravi di fornire una dimostrazione, si è trovato che l’assioma 5 della geometria euclidea – l’assioma delle parallele – non si poteva dimostrare come se fosse un teorema ma che anzi si poteva anche negare, addirittura in due modi, originando due nuovi sistemi indpendenti: le due geometrie non euclidee, quella di Riemann e quella di Bolyai/Lobacevskij.

In generale è stato dimostrato da Kurt Gödel che questo assioma è un punto debole come un punto debole ce l’ha qualsiasi altro sistema assiomatico (teoremi di incompletezza). Quindi in questo Gödel ha messo una pietra sopra sul fatto che in ogni sistema assiomatico ci sia un’affermazione che non può essere né dimostrata né negata all’interno dello stesso sistema.

Infatti si costruisce un altro sistema con una negazione del V postulato che ad esempio generi la geometria iperbolica e anche all’interno di questa non è dimostrabile né confutabile. Lo stesso vale per la geometria ellittica.

Non c’è niente da fare. Però questo teorema ha fatto finalmente in modo che la questione si potesse considerare chiusa una volta per sempre.

Ma in questo caso invece, come disse Paul Erdős, matematico ungherese, a proposito della congettura di Collatz

“La matematica non è ancora pronta per risolvere problemi del genere”

Paul Erdős

La congettura

La congettura di Collatz afferma che la successione così definita:

	x_{n+1} = 
	\begin{cases}
	3x_n + 1, & x_n \mod 2 = 0 \\
	x_n/2 & x_n \mod 2 = 1
	\end{cases}

converge sempre a 1 per n \ge N \in \mathbb{N} . Ricordo che x_n \mod 2 = 0 vuol dire che x_n è pari e x_n \mod 2 = 1 vuol dire che x_n è dispari.

Python: la libreria matplotib

Ora per divertirmi un po’ a vedere come funziona questa successione ho utilizzato Python e la libreria matplotlib che avevo già utilizzato per lo studio dell’apprendimento delle reti neurali.

È semplice installarla come libreria stand-alone per Python 3:

$ git clone git@github.com:matplotlib/matplotlib.git
$ cd matplotlib/
$ python3 setup.py install

Sorgente Python

Dopodiché la uso in un programma che semplicemente calcola la successione e la visualizza su un grafico

!/usr/bin/python3
import matplotlib.pyplot as plt

a = input("Dimmi un numero: ")
print("Successione di Collatz a partire da a=",a)
z = int(a)
s = []
s.append(z)

while (z != 1):
   print(z,", ")
   if (z % 2 == 0):
      z /= 2
   else:
      z = 3*z + 1
      
   s.append(z)
# la congettura d Collatz afferma che si esce sempre dal ciclo

# disegna
x = range(len(s))
plt.plot(x, s, label="Successione di Collatz")
plt.xlabel('iterazioni')
plt.ylabel('successione')
plt.title('Congettura di Collatz')
plt.legend() 
plt.grid(True)
plt.show()

Ci si può divertire a vedere il comportamento di questa succcessione che sembra davvero imprevedibile per numeri che non fanno parte della successsione delle potenze di 2. Ad esempio il 103 genera questo andamento

Matematica: Congettura di Collatz: un esempio di successione per punto iniziale x1=103.
Matematica: Successione per x_1= 103

Wi-Fi: come visualizzare la potenza del segnale

Wi-Fi
Wi-Fi

Utilizzo il mio smartphone come hotspot wireless per connettermi a Internet con i dispositivi di casa. Stamattina ho voluto controllare quale fosse la potenza del segnale Wi-Fi perché volevo trovare la posizione ottimale dell’hotspot rispetto alla mia postazione di lavoro.

Prima mi sono studiato come accedere al dato della potenza del segnale Wi-Fiin ingresso dell’antenna (dettagli qui) e poi ho riportato questo dato in funzione del tempo in un grafico animato in modo tale da poter girar per casa e posizionarlo dove ho un segnale più forte, e non è detto che sia accanto al PC 😉

Campionamento della potenza del segnale Wi-Fi

La potenza istantanea del segnale Wi-Fi si può visualizzare con il comando

$ iwconfig wlp2s0
wlp2s0 IEEE 802.11 ESSID:"HUAWEI Y6 2019"
Mode:Managed Frequency:2.412 GHz Access Point: F2:E4:A2:93:8C:0C
Bit Rate=72.2 Mb/s Tx-Power=22 dBm
Retry short limit:7 RTS thr:off Fragment thr:off
Power Management:on
Link Quality=61/70 Signal level=-49 dBm
Rx invalid nwid:0 Rx invalid crypt:0 Rx invalid frag:0
Tx excessive retries:171 Invalid misc:9250 Missed beacon:0

Come si vede, la linea

Link Quality=61/70 Signal level=-49 dBm

contiene l’informazione desiderata. Se spegniamo l’hotspot l’output del comando è invece:

$ iwconfig wlp2s0
wlp2s0 IEEE 802.11 ESSID:off/any
Mode:Managed Access Point: Not-Associated Tx-Power=22 dBm
Retry short limit:7 RTS thr:off Fragment thr:off
Power Management:on

Quindi un modo se volete un po’ grezzo di accedere velocemente alla potenza del segnale Wi-Fi è fare il parsing dell’output di questo comando. L’idea è di lanciarlo con regolarità in modo da costruire un campione di dati da visualizzare in qualche modo in tempo reale.

Il primo programma che ho scritto è questo:

#!/usr/bin/python3
#
# Found in: https://www.calazan.com/how-to-continuously-monitor-your-wi-fis-signal-strength-in-ubuntu/
# Mutatis mutandi
#

import subprocess
import time
import argparse

parser = argparse.ArgumentParser(description='Display WLAN signal strength.')
parser.add_argument(dest='interface', nargs='?', default='wlan0',
                    help='wlan interface (default: wlan0)')
args = parser.parse_args()

print('\n---Press CTRL+Z or CTRL+C to exit---\n')

while True:
    cmd = subprocess.Popen('iwconfig %s' % args.interface, shell=True,
                           stdout=subprocess.PIPE)
                           
    for line in cmd.stdout:
        l = str(line)
        if 'Link Quality' in l:
            print (l),
        elif 'Not-Associated' in l:
            print ('No signal')
    time.sleep(1)

Aspetti importanti di questo script sono il package subprocess che consente a Python di lanciare un comando del sistema operativo, in questo caso

iwconfig wlp2s0

Il package argparser fornisce una serie di utilissime funzioni per maneggiare le linee di comando (definire i parametri di avvio, la loro obbligatorietà, i valori di default e finanche la documentazione di help).

Il package itertools fornisce il metodo count() che realizza un contatore progressivo che ci serve per etichettare i campioni di segnale, campioni che vengono prelevati con regolarità utilizzando le funzione del package time..

In sostanza il metodo subprocess.Popen() lancia il comando e il dato desiderato si trova nell’output del comando che comunque non è una stringa e va convertito per potere fare il parsing. Il parsing si utilizza quando il dato è annegato nella sporcizia, per cui ritengo questo mio metodo un metodo piuttosto sporco.

In questo embrione di programma ho il seguente ouput

—Press CTRL+Z or CTRL+C to stop.—

b' Link Quality=70/70 Signal level=-31 dBm \n'
b' Link Quality=70/70 Signal level=-31 dBm \n'
b' Link Quality=70/70 Signal level=-36 dBm \n'
b' Link Quality=70/70 Signal level=-32 dBm \n'
b' Link Quality=70/70 Signal level=-32 dBm \n'

Il dato interessante si trova in ogni riga dalla posizione 45 alla posizione 48.

Con una piccola modifica ci facciamo stampare solo il dato desiderato

--Press CTRL+Z or CTRL+C to stop.---
-32
-32
-35
-31
-31
-35
-35
-35
-36

Visualizzazione del segnale Wi-Fi utilizzando matplotlib

Ora invece di stampare questi valori, li voglio disporre su un grafico. Utilizzo la libreria matplotlib. Il sorgente completo è il seguente

#!/usr/bin/python3
#
# Adopted for reading wifi power signal and plotting it
#
# @author: marco@betaingegneria.it
# @copyright: GPL Affero v.3
# @date 2020-09-25

import subprocess
import argparse
import matplotlib.pyplot as plt
from itertools import count
from matplotlib.animation import FuncAnimation

# init graphics stuff
plt.style.use('seaborn')

x=[] # time series
y=[] # power samples
index = count()

# init wlan signal reader
# parse line command arguments
parser = argparse.ArgumentParser(description='Display WLAN signal strength.')

# interface
parser.add_argument(dest='interface', nargs='?', default='wlp2s0',
                    help='wireless.py [interface=wlp2s0] [delta=800]')

# sampling period in ms
parser.add_argument(dest='delta', nargs='?', default='800',
                    help='wireless.py [interface=wlp2s0] [delta=800]')
                    
args = parser.parse_args()

if (int(args.delta) < 200):
    print('Please, choose a value >= 200 for delta')
    exit()

print('Close the window to exit')

def animate(i):
    """ read the wifi power in dBm and plot """
    x.append(next(index))
    
    cmd = subprocess.Popen('iwconfig %s' % args.interface, shell=True,
                       stdout=subprocess.PIPE)
                       
    for line in cmd.stdout:
        l = str(line)
        if 'Link Quality' in l:
            y.append(int(l[45:48]))
        elif 'Not-Associated' in l:
            y.append(None)

    plt.cla()
    plt.plot(x, y, '-', marker='.', label='WiFi signal strenght in dBm')
    plt.legend(loc='upper left')
    plt.tight_layout()
    
    # ring a bell every sample
    #print('\a')

ani = FuncAnimation(plt.gcf(), animate, interval=args.delta)    

plt.show()

Un po’ di parafrasi: la funzione animate() contiene il codice che legge la potenza e, eseguendo il parsing estraiamo il valore in dBm da accodare alla lista y, mentre nella lista x accodiamo i valori del contatore.

Il plot viene fatto utilizzando come skin lo stile seaborn, che comprende la griglia in negativo (bianco su grigio).

Infine ho utilizzato il metodo matplotlib.animation() che può essere configurato per un aggiornamento ogni delta millisecondi – ci sganciamo quindi dalla libreria time – , variabile che gestiamo come parametro di input.

Il risultato è questo

Andamento della potenza segnale wireless (max -30dB) provando a spostare l'hotspot in giro per la stanza
Andamento della potenza segnale Wi-Fi provando a spostare l’hotspot in giro per la stanza

Se si spegne l’hotspot o si esce dal suo range di segnale non verrà plottato alcun dato.

Link utili

Lagrangiana

Qualche tempo fa ho acquistato al CERN di Ginevra questa T-shirt che di tanto in tanto indosso:

La lagrangiana del Modello Standard
La lagrangiana del Modello Standard

La formula scritta sulla maglietta è la lagrangiana del modello standard.

Invariabilmente, ogni volta che la indosso, mi chiedono: cos’è una lagrangiana? Oppure cosa vuol dire Modello Standard?

La cosa mi fa piacere perché ragionare di Fisica mi piace sempre un sacco.

La lagrangiana nella Meccanica Classica

Una breve introduzione alla lagrangiana nella Meccanica Classica la trovate qui. Meglio che la leggiate, vi serve per capire un po’ meglio quello che segue.

In sostanza è una funzione di posizione e velocità di un sistema meccanico classico che ci aiuta a scrivere le equazioni del moto.

La lagrangiana in Meccanica Quantistica

La lagrangiana della maglietta è un formalismo che si usa in teoria dei campi ed è l’estensione a questa disciplina del concetto che Lagrange elaborò per risolvere problemi di Meccanica Classica (lui non la chiamava così, siamo noi che abbiamo dovuto attaccare l’aggettivo “classica” per distinguerla dalla Meccanica Relativisitica o dalla Meccanica Quantistica) in sistemi con un numero finito di variabili – o gradi di libertà . Essa dal punto di vista matematico è un oggetto completamente diverso da quello della Meccanica Classica, è una funzione di densità: in questo caso la lagrangiana si applica ai continui e ai campi, che hanno un numero infinito di gradi di libertà.

A grandi linee ogni riga della maglietta è un pezzo della teoria del Modello Standard, il modello che spiega tre delle 4 forze fondamentali dell’Universo:

  • la forza elettromagnetica – che ti fa tenere il cane per il guinzaglio,
  • la forza forte, che tiene insieme i nuclei degli atomi,
  • la forza debole, che permette alle particelle di trasformarsi,

La forza gravitazionale, che ci tiene attacati per terra e move il Sole e l’altre stelle (cit.), finora è la grande esclusa dal Modello Standard.

La lagrangiana prevede 6 termini.

Primo termine -\frac{1}{4}F_{\mu\nu}F^{\mu\nu}

Questo termine è il prodotto scalare del tensore dell’intensità di campo F_{\mu\nu} contenente la codifica matematica di tutte le particelle di interazione – eccetto il bosone di Higgs -, dove \mu e \nu sono indici di Lorentz che rappresentano le componenti dello spaziotempo (t, x, y, z). Contiene la formulazione necessaria affinché queste particelle esistano e descrive come interagiscono tra loro. I contenuti differiscono a seconda delle proprietà delle particelle di interazione. Ad esempio, i fotoni, le particelle di interazione dell’interazione elettromagnetica, non possono interagire tra loro, perché non hanno carica elettrica. Pertanto, il contributo dell’interazione elettromagnetica consiste solo in un termine cinetico, che è la base dell’esistenza di fotoni liberi. La descrizione dei gluoni e dei bosoni dell’interazione debole comprende invece anche i termini di interazione oltre ai termini cinetici. I gluoni, ad esempio, sono essi stessi carichi di “colore” e possono quindi anche interagire tra loro.

Questo porta a una conseguenza entusiasmante: il Modello Standard della fisica delle particelle prevede l’esistenza di stati legati costituiti solo da gluoni, le cosiddette ‘glueballs‘ (letteralmente: palle di colla). Tuttavia, finora nessun esperimento ha rilevato le glueballs.

Il termine i\bar{\psi} D\!\!\!\!/\psi

Questo termine descrive invece come le particelle di interazione interagiscono con le particelle di materia. I campi \bar{\psi} e \psi descrivono (anti)quark e (anti)leptoni. Questo termine ad esempio regola l’annichilazione elettrone-positrone e il decadimento beta.

Il termine h.c.

h.c. sta per hermitian conjugate, coniugato hermitiano: un operatore o una matrice è hermitiana quando il suo prodotto con la controparte complessa coniugata è una quantità reale.

Siccome quando facciamo misure vediamo numeri reali, è necessario che tutte le quantità complesse abbiano il corrispettivo coniugato in modo tale che il prodotto sia un numero reale. Questo è un assioma della Meccanica Quantistica e da’ conto del fatto che le misurazioni sono sempre numeri reali. Il termine h.c. va eventualmente aggiunto al secondo termine (interazione bosone – particella) qualora questo dia un numero complesso. In realtà il secondo termine è sempre un numero reale (più precisamente è un operatore autoaggiunto). Lo chiamano anche hot coffee (caffè che scotta).

Piccolo dizionario: i bosoni (particelle che seguono la statistica di Bose-Einstein)sono le particelle mediatrici della forza (la più famosa è il fotone, che veicola l’interazione elettromagnetica). I fermioni (particelle che seguono la statistica di Fermi-Dirac) sono le particelle di materia ordinaria (protoni ed elettroni per esempio).

Il termine \psi_i y_{ij}\psi_j\phi

Il quarto termine descrive l’accoppiamento di una particella di materia con il campo di Higgs \phi per acquisire massa. y_{ij} è detto campo di Yukawa, vedi bibliografia.

Il termine |D_\mu\phi|^2

Il quinto termine descrive l’accoppiamento di una particella di interazione con il campo di Higgs.

Tuttavia le uniche particelle di interazione (dette anche bosoni) che hanno massa sono i bosoni dell’interazione debole – previste teoricamente da Abdus Salam e scoperte da Carlo Rubbia, per cui questo termine descrive proprio loro (W^{\pm}, Z_0).

Il termine -V(\phi)

L’ultimo termine descrive il potenziale del campo di Higgs (detto più precisamente campo di Brout–Englert–Higgs).

Nella maggior parte delle cose che ci accadono quotidianamente, l’unico termine ad entrare in azione è il secondo. I fotoni non ottengono massa dal meccanismo di Higgs, mentre i gluoni sono privi di massa perché non si accoppiano al campo di Brout-Englert-Higgs.

Come vedete in questa lagrangiana non si parla di gravità. includere la gravità nella teoria di campo quantistica è una delle sfide che stanno impegnando i fisici e i matematici da mezzo secolo e ancora non si vede la luce in fondo al tunnel.

Inoltre il modello standard descrive perfettamente la materia, ma ciò che vediamo è solo il 5% della materia totale, per cui il resto cos’è e come funziona?

Per chi volesse approfondire, in bibliografia c’è un bell’articolo, senza addentrarsi troppo nei dettagli.

Fatemi siete arrivati fin qui se vi è piaciuto l’articolo.

Ringrazio Corrado Tagliente per avermi spronato a migliorare l’articolo.

Bibliografia

Pillola Liste Python: quando append() produce una lista di elementi tutti uguali

Liste Python: l'uso del metodo append()
Liste Python: l’uso del metodo append()

Liste Python: provando a costruire una lista, con un metodo learn di una certa classe P che ritorna una lista

for i in range(1,5):
    w=P.learn()
    print(type(w))
    hist_w.append(w)
    print("hist_w", hist_w)

i valori di w ritornati ad ogni ciclo erano del tipo

[-1.7968410695441766, 1.1, 0.20315893045582345]
[-2.4943448781251716, 1.1, -0.4943448781251717]

ma la lista hist_w al primo ciclo conteneva

[[-1.7968410695441766, 1.1, 0.20315893045582345]]

Al secondo ciclo conteneva

[[-2.4943448781251716, 1.1, -0.4943448781251717],
[-2.4943448781251716, 1.1, -0.4943448781251717]]

e così via, cioè anziche venire aggiunto l’ultimo elemento (anche lui una lista) alla lista, venivano sostituiti tutti gli elementi della lista con l’ultima lista calcolata.

Il problema è che stavo copiando ogni volta il riferimento alla variabile w (che è lo stesso ad ogni ciclo) e non il contenuto della variabile stessa (che cambia ad ogni ciclo):

[<riferimento a w>, <riferimento a w>, …]

Per disinnescare l’errore ho fatto così:

for i in range(1,5):
    w=P.learn()
    print(type(w))
    hist_w.append(w[:])
    print("hist_w", hist_w)

Notate il [:] accanto al nome della variabile.

Liste Python: altre risorse utili

Strutture dati Python

Git in pillole: il file .gitignore

gitignore
git

.gitignore o .git/info/exclude? Vediamo le differenze e il perché a volte Git sembra ignorare le nostre direttive sull’esclusione di alcuni file dal ciclo di vita del software.

Differenza tra .gitignore e .git/info/exclude

Entrambi i file servono a Git per stabilire quali file non entrano nel ciclo di versionamento.

Essi agiscono ad un diverso livello.

Il file .git/info/exclude serve per escludere i file nel proprio clone locale; se qualcuno che collabora con noi non ha escluso gli stessi file che abbiamo escluso noi, potremmo ritrovarci – se facciamo un clone o un fetch – file che sono entrati nel versionamento nell’origin ma che io non ho perché esclusi, o viceversa. Quindi è bene, quando si devono escludere dei file globalmente (per tutti i programmatori) agire sul file .gitignore che invece viene versionato – per cui ogni repository locale se lo trova. Se dobbiamo agire in modo più granulare sui file da versionare (o meno) directory per directory, è possibile scrivere un apposito file .gitgnore in ogni directory in cui serve.

Git sembra ignorare la direttiva di ignorare file

Ho messo dei file da escludere nel file .git/info/exclude (o in .gitignore) ma continuo a vederli come new file quando eseguo il comando git status:

$ git status
Sul branch master
Your branch is up to date with 'origin/master'.

Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        modified:   app/Http/Controllers/BaseController.php
        new file:   storage/logs/laravel-2020-07-22.log
        new file:   storage/logs/laravel-2020-07-23.log
        ...
  

In particolare non voglio che i file di log entrino nel versionamento. Ho però inserito correttamente la riga

storage/logs*

in entrambi i file .gitignore e .git/info/exclude. Come mai Git continua a mostrarmeli come file da versionare?

Git utilizza il file .gitignore nel momento in cui aggiunge i file; una volta aggiunti all’indice dei file da versionare Git continua a considerarli tali, a dipetto di modifiche successive dei file di gitignore. Quindi ci sono due modi per uscire dall’impasse:

  • cancellare fisicamente i file, ma è l’opzione più stupida
    git rm storage/logs/*
  • cancellare la cache:
    git rm --cached storage/logs/*

Infatti l’opzione --cached indica a Git di togliere i file dall’indice ma non dal file system.

Ho trovato queste indicazioni in un paio di risposte di fourm 1 e 2.

Altri articoli del blog su git

Oracle Connection Pooling, ovvero come gestire gli accessi concorrenti a database con una coda.

Oracle connection pooling
Oracle connection pooling

Negoziare una connessione con un database è una operazione non banale che richiede una consistente attività per la realizzazione del collegamento sicuro, autenticato e la messa a disposizione delle risorse del database all’applicazione che ne fa uso. Ho esperienza di questo fatto soprattutto in ambito Java e Oracle ma le considerazioni da fare sono tutto sommato agnostiche e quindi indipendenti dalle piattaforme utilizzate. Tuttavia gli esempi sono in Java.

In ambito concorrente, come una applicazione web, questa operazione di negoziazione rischia presto di diventare un collo di bottiglia se si rimane nello schema 1 richiesta = 1 nuova connessione a DB.

Per risolvere questo problema è stato messa a punto la tecninca Oracle connection pooling (ovvero qui vediamo quella di Oracle, ma in realtà è una tecnica che si può applicare anche ad altri DBMS).

L’idea è quella di utilizzare una coda (in questo ambito definita come pool) nella quale mantenere un numero finito di connessioni riutilizzabili che vengono in continuazione prelevate dalla coda quando servono e rimesse nella coda al termine del loro utilizzo.

Oracle Connection Pooling: il caso d’uso

Supponiamo che arrivino due richieste quasi simultanee:

  1. Richiesta 1 (es. https://mysite.com/authenticate) la quale richiede collegamento al db per effettuare una autenticazione utente: in questa richiesta viene aperta una nuova connessione al database e viene lanciata la query sulla tabella utenti. Dopo aver acqusito il recordset, l’applicazione può dismettere la connessione invocando il metodo close()
  2. Richiesta 2 (es. https://mysite.com/articles/get/AB123) che deve eseguire una lettura di una tabella. L’applicazione apre una connessione ex novo (con il conseguente impegno di risorse e di tempo), lancia l’interrogazione e recupera il recordset.

Non sarebbe più efficiente per la Richiesta 2, qualora arrivasse dopo la conclusione della prima richiesta, riutilizzare la connessione aperta dalla Richiesta 1? Se la richiesta evitasse di chiamare la close() e invece “mettesse via” la connessione da qualche parte, la richiesta 2 potrebbe riutilizzarla senza dover negoziare un’altra volta con il DBMS username/password e caricamento driver.

Oracle connection Pooling: funzionamento

Una struttura dati efficiente per mettere via dati che si ritiene di usare di nuovo a breve, può essere una coda, in particolare una coda FIFO. Che nel gergo dei database si chiama Connection Pool. Questa coda conterrà descrittori di risorse DBMS.

Il funzionamento di questa coda è il seguente. Partiamo da una coda vuota.

Arriva il primo processo (una richesta HTTP: per esempio una login) che richiede all’applicazione di collegarsi al database. Siccome la coda è vuota, viene giocoforza negoziata una connessione nuova con il database, chiamiamola Connessione 1. Quando l’interrogazione è stata fatta e quindi la login è eseguita, la connessione non viene chiusa, bensì viene salvato il descrittore con un push() nella coda, che finora era ancora vuota.

Arriva il secondo processo che necessita di una connessione al DBMS e quello che fa prima di tutto è controllare se nella coda ci sono connessioni disponibili. Supponiamo che la login sia già stata fatta e quindi nella coda ci sia la connessione 1 rilasciata dal primo processo. Tutto ciò che deve fare il processo 2 è lanciare la query senza autenticarsi di nuovo; quindi serviamo due processi con una sola connessione.

Se, viceversa, il processo 2 arriva quando la login è ancora in corso, quindi la connessione 1 è ancora impegnata, in questo caso il processo 2 dovrà aprire una connessione 2.

Ma questo meccanismo fa sì che, dopo un po’ di tempo, la probabilità di trovare una connessione libera nella coda sia molto maggiore e quindi il numero di negoziazioni dirette è destinato a calare drasticamente.

Una strategia ancora migliore è questa: se all’avvio dell’applicazione server inizializzaziamo il pool costruendo e mettendo già via un certo numero di connessioni nella coda, risparmiamo tempo ad applicazione avviata.

Ogni volta che un processo preleva una connessione dalla coda, fa un pull(), ovvero toglie la connessione dalla coda; quando ha terminato, opera un push() e la rimette nella coda. Se il numero di processi concorrenti è maggiore della dimensione della coda fino a quel momento, viene negoziata una nuova connessione, altrimenti si fa più velocemente un pull().

Questo meccanismo deve essere gestito; ossia si deve sollevare l’applicazione dal negoziare nuove connessioni, perché dovrà essere tutto supervisionato dal processo di gestione della coda, che è un oggetto della classe ConnectionPool. L’applicazione dovrà solo limitarsi a chiedere una connessione al pool, e il pool in ogni caso gliela concederà (sia essa una connessione riciclata o una nuova di zecca), senza che l’applicazione debba interloquire direttamente con il database.

Per rendere poi più efficiente l’uso della memoria, si può fare a meno di allocare una coda dinamica (che implica continue chiamate alla JVM per farsi allocare memoria a runtime), ma utilizzzare invece un array di lunghezza fissa, in cui vengono impilate tante connessioni quante ne servono: all’inizio supponiamo che la coda sia vuota, viene fatto il push() di una nuova connessione, marcata con Active e consegnata al processo, che la potrà usare. Quando il processo che l’ha utilizzata la rilascia, il gestore del pool la dichiarerà Idle rimettendola a disposizione. Però non è che la inserisce nuovamente nel pool, semplicemente le cambia lo stato.

Tuttavia nell’implementazione di esempio che vedremo, viene utilizzata un’altra tecnica ancora: vengono impiegati due vettori; quello delle connessioni disponibili (o idle) e quello delle connessioni attive (active).

Il processo successivo che arriva a chiedere connessioni, si farà dare l’ultima connessione idle resasi disponibile (comportamento FIFO).

Oracle connection Pooling: esempio applicativo

Questo esempio è liberamente tratto (e semplificato) da Java Made So Easy.

Iniziamo dunque definendo la classe ConnectionPool:

package connectionPooling;
 
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Vector;
 
public class ConnectionPool implements Runnable {
    // i parametri di connessione
    private String driver, url, username, password;
    // la dimensione massima del pool
    private int maxConnections; 
    // le 2 code delle connessioni idle e active
    public Vector<Connection> idleConnections, activeConnections; 

    // il costruttore
    public ConnectionPool(
                  String driver, String url, String username,
                  String password, int maxConnections, int initialConnections
           ) throws SQLException {
           this.driver = driver;
           this.url = url;
           this.username = username;
           this.password = password;
           this.initialConnections = initialConnections;
           this.maxConnections = maxConnections;

           // in questo esempio il pool è mantenuto su due vettori:
           // - quello delle connessioni disponibili (o idle: pigre, nullafacenti);
           // - quello delle connessioni impegnate (o active);
           idleConnections = new Vector<Connection>(initialConnections);
           activeConnections = new Vector<Connection>();
           // qui opzionalmente preparo un certo numero di connessioni già pronte
           for (int i = 0; i < initialConnections; i++) {
                  idleConnections.addElement(makeNewConnection());
           }
    }

Il metodo fondamentale qui è makeNewConnection() con il quale costruiamo una nuova connessione “vera”; ovviamente lo dichiariamo private per impedire al programma chiamante di negoziare connessioni direttamente con il DBMS attraverso di essa:

private Connection makeNewConnection() throws SQLException {
           try {
                  // Carica il database driver
                  Class.forName(this.driver);
                  // Apri la connessione al db
                  Connection connection = DriverManager.getConnection(this.url, this.username,
                               this.password); 
                  return (connection);
           } catch (Exception cnfe) {
                  cnfe.printStackTrace();
                  throw new SQLException(
                               "ConnectionPool:: SQLException encountered:: "
                                             + cnfe.getMessage());
           }
    }

Come visto sopra questo metodo viene chiamato al deploy del connectioonPool per inizializzare un certo numero di connessioni già pronte per l’uso (che passo al costruttore).

Ora dobbiamo gestire il pool, ovvero consegnare al processo che ne fa richiesta una connessione idle, toglierla dal vettore delle idle e metterla in quello delle active:

/**
     * Method to return Connections
     */
    public synchronized Connection getConnection() throws SQLException {
           if (!idleConnections.isEmpty()) {
                  Connection existingConnection = (Connection) idleConnections
                               .lastElement();
                  int lastIndex = idleConnections.size() - 1;
                  // toglie la connessione dal vettore delle pigre:
                  idleConnections.removeElementAt(lastIndex);
                  // ... e la aggiunge al vettore delle attive:
                  activeConnections.addElement(existingConnection);
                  return (existingConnection);
           } else {
                  // se non ci sono più connessioni pigre, ne creo una di nuova: 
                  return makeNewConnection();
           }
    }

Poniamo attenzione sul fatto che il metodo getConnection() è definito come synchronized, per cui molte richieste pressoché simultanee verranno arbitrate in modo che le connessioni siano consegnate distintamente secondo il loro ordine di arrivo.

Può accadere, alla fine, che i processi esauriscano tutte le connessioni del pool: in questo caso il vettore delle connessioni active sarà pieno e quello delle idle sarà vuoto; si potrebbe gestire anche questa situazione ma, in questa fase in cui cerchiamo di capire come funziona il meccanismo, semplicemente notifichiamo che il pool è pieno.

                  if ((totalConnections() >= maxConnections) {
                        throw new SQLException("Connection limit reached");
                  }

dove totalConnection() è un count degli elementi del vettore activeConnections più il count degli elementi del vettore idleConnections.

Alla fine il programma chiamante utilizzerà il metodo getConnection() per comunicare con il pool, mentre la classe ConnectionPool utilizzerà il metodo (privato) makeConnection() per comunicare con il DBMS.

Così abbiamo operato la separazione tra applicazione e DBMS.

Ci manca solo un metodo per liberare una connessione (cioè toglierla dal vettore delle connesioni active e rimetterla in quello delle connessione idle), lo chiamiamo free():

  /**
     * Method to free the Connections
     */
    public synchronized void free(Connection connection) {
           activeConnections.removeElement(connection);
           idleConnections.addElement(connection);
    }

Alla fine siamo pronti ad utilizzare questa infrastruttura nell’applicazione; dobbiamo creare un oggetto istanza della classe ConnectionPool che mettterà a disposizione connessioni già pronte prelevabili con il metodo getConnection():

package connectionPooling;
 
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
 
/** Copyright (c), Ankit Mittal JavaMadeSoEasy.com */

public class PreparedStatementUseConnectionPooling {

    public static void main(String... arg) throws SQLException {
            ConnectionPool connectionPool = new ConnectionPool(
                        "oracle.jdbc.driver.OracleDriver",
                        "jdbc:oracle:thin:@localhost:1521:orcl", 
                        "foo", 
                        "bar",
                        10, 5);
 
           Connection dbConn = connectionPool.getConnection();
           System.out.println("Sono pronte le connessioni dalla classe ConnectionPool");
           
           PreparedStatement prepStmt = dbConn
                        .prepareStatement("select ID, NAME from EMPLOYEE");
           
           ResultSet rs = prepStmt.executeQuery();
           while (rs.next()) {
                  System.out.print(rs.getInt("ID") + " ");
                  System.out.println(rs.getString("NAME"));
           }
 
           if (rs != null)
                  rs.close(); // close resultSet
           if (prepStmt != null)
                  prepStmt.close(); // close PreparedStatement
 
           connectionPool.free(dbConn);
           System.out.println("Rilasciata la connessione dalla classe ConnectionPool");
    }
}
 

Si noti che il programma chiamante, dopo la connessione impartisce comandi direttamente al DBMS; il ConnectioPool si intromette tra di loro solo al momento dell’acquisizione di nuove connessioni (o della rimozione di un connessione che non serve più).

Per ulteriori dettagli implementativi si faccia riferimento all’articolo citato all’inizio.

Adesso il funzionamento di un pool dovrebbe essere almeno un pelino più chiaro. Almeno per me lo è stato.

Dati COVID-19 nuovamente online

Ho sistemato un errore che si era manifestato nel cruscotto dei dati relativi alla pandemia tuttora in corso.

L’errore si è verificato in seguito ad una modifica del tracciato dati messo online dalla Protezione Civile e aveva temporaneamente reso non operativo il cruscotto.

Potete nuovamente consultarli (dati nazionali e regionali) a questo link:

Python in pillole – parte 3: disegnare frecce

Python logo

Python programming skill terza parte: disegnamo in modalità testo come ultimo pattern quattro frecce:

right arrow
*                    
* *                  
* * *                
* * * *              
* * * * *            
* * * *              
* * *                
* *                  
*                    
                     
left arrow
                     
                  *  
                * *  
              * * *  
            * * * *  
          * * * * *  
            * * * *  
              * * *  
                * *  
                  *  
upward arrow
                     
                     
                     
                     
                     
        *            
      * * *          
    * * * * *        
  * * * * * * *      
* * * * * * * * *    
downward arrow
* * * * * * * * *    
  * * * * * * *    
    * * * * *    
      * * *    
        *    
           

Esercizio Python 7 – freccia verso destra (right arrow)

"""
print right arrow
*
* *
* * *
* *  
* 

e.g.
  0 1 2 3 4 5 6 7 8 9         i  test    N-1-i
0 *                           0, j<=0    9
1 * *                         1, j<=1    8
2 * * *                       2, j<=2    7
3 * * * *                     3, j<=3    6
4 * * * * *                   4, j <5    5
5 * * * *                     5, j <4    4
6 * * *                       6, j <3    3
7 * *                         7, j <2    2
8 *                           8, j <1    1
9                             9, j <0    0
"""
print("right arrow")
for i in range(N):
    for j in range(N):
        if j <= i and j < N - 1 - i:
            print("*"),
        else:
            print(" "),
    print(" ")  # a capo

Ho stampato un tracing e ho riportato tutti i valori delle variabili per le varie configurazioni disegnate. Come si vede, si tratta di combinare le condizioni che compaiono negli esercizi 3 e 6 (BLT e TLT), solo che sostituisco la condizione j <= N - 1 - i con j < N - 1 - i in modo da non disegnare la diagonale BLTR che risulterebbe col disegnare una freccia “spuntata”.

Esercizio Python 8 – freccia verso sinistra (left arrow)

"""
print left arrow
    *
  * *
* * *
  * *  
    * 
    
e.g.
  0 1 2 3 4 5 6 7 8 9      i  test    N-1-i
0                   *      0, j>=9    9*
1                 * *      1, j>=8    8*
2               * * *      2, j>=7    7*
3             * * * *      3, j>=6    6*
4           * * * * *      4, j>=5    5*
5             * * * *     *5, j> 5    4
6               * * *     *6, j> 6    3
7                 * *     *7, j> 7    2
8                   *     *8, j> 8    1
9                         *9, j> 9    0 
"""
print("left arrow")
for i in range(N):
    for j in range(N):
        if j >= i and j > N - 1 - i:
            print("*"),
        else:
            print(" "),
    print(" ")  # a capo

Per girare la freccia a sinistra è necessario ribaltare entrambe le condizioni di test:

  • da j<=i a j>=i
  • da j <= N - 1 - i a j > N - 1 - i

L’assenza dell’= sulla seconda condizione, al solito, evita il disegno della doppia punta.

Possiamo indovinare che anche per le frecce up e down si dovrà fare lo stesso…

Esercizio Python 9 – freccia verso l’alto (upward arrow)

"""
print upward arrow
    *  
  * * *
* * * * * 

e.g.
  0 1 2 3 4 5 6 7 8 9
0
1
2
3
4                       N-1-i  test  i    
5         *                 4 <= j < 5
6       * * *               3 <= j < 6
7     * * * * *             2 <= j < 7
8   * * * * * * *           1 <= j < 8
9 * * * * * * * * *         0 <= j < 9

"""
print("upward arrow")
for i in range(N):
    for j in range(N):
        if N - i - 1 <= j < i:
            print("*"),
        else:
            print(" "),
    print(" ")  # a capo

Qui è ormai evidente: è l’intersezione dei due esercizi BLT e BRT (esercizi 3 e 5). L’ultimo esercizio è la freccia verso il basso e, ormai, tutti gli arcani dovrebbero essere svelati e possiamo dire “com’era facile!”

Esercizio Python 10 – freccia verso il basso (downward arrow)

"""
print downward arrow
* * * * * 
  * * *
    *  

e.g.
  0 1 2 3 4 5 6 7 8 9     i   test  N-1-i
0 * * * * * * * * *       0   <=j<  9
1   * * * * * * *         1   <=j<  8
2     * * * * *           2   <=j<  7
3       * * *             3   <=j<  6
4         *               4   <=j<  5
5
6
7
8
9 
"""
print("downward arrow")
for i in range(N):
    for j in range(N - i):
        if i <= j < N - 1 - i:
            print("*"),
        else:
            print(" "),
    print(" ")  # a capo

Spero abbiate trovato divertenti questi piccoli esercizi (sì… anche se alla fine sono un po’ silly).

Alle prossime pillole!

Altre pillole Python sul disegno di frecce

Disegnare frecce 1Disegnare frecce 2

Link utili

Python.org

Python in pillole – parte 2: disegnare triangoli

Python logo
Python logo

Python programming skill seconda parte: un po’ più laborioso è disegnare questi quattro triangoli. Ma neanche tanto, vedrete.

Parte II – disegnare triangoli con Python

Bottom Left Triangle

BLT
*  
* *  
* * *  
* * * *  
* * * * *  
* * * * * *  
* * * * * * *  
* * * * * * * *  
* * * * * * * * *  
* * * * * * * * * *  

Top Right

TRT
* * * * * * * * * *  
  * * * * * * * * *  
    * * * * * * * *  
      * * * * * * *  
        * * * * * *  
          * * * * *  
            * * * *  
              * * *  
                * *  
                  * 

Bottom Right

BRT
                  *  
                * *  
              * * *  
            * * * *  
          * * * * *  
        * * * * * *  
      * * * * * * *  
    * * * * * * * *  
  * * * * * * * * *  
* * * * * * * * * *  

e infine Top Left

TLT
* * * * * * * * * *  
* * * * * * * * *    
* * * * * * * *      
* * * * * * *        
* * * * * *          
* * * * *            
* * * *              
* * *                
* *                  
*         

Li ho messi in quest’ordine perché sono due metà del quadrato diviso dalla stessa diagonale (TLBR nel primo, TRBL nel secondo).

Esercizio 3 – disegnare un triangolo BLT

print("BLT")
for i in range(N):
    for j in range(N):
        if i >= j:
            print("*"),
        else:
            print(" "),
    print(" ")  # a capo

Qui è evidente che l’esercizio 3 si ricava dall’esercizio 1 semplicemente sostituendo la condizione i=j con i>=j ma anche estendendo la scansione di j a tutto l’intervallo 0..N-1.

Esercizio 4 – disegnare un triangolo TRT

print("TRT")
for i in range(N):
    for j in range(N):
        if i <= j:
            print('*'),
        else:
            print(" "),
    print(" ")  # a capo

Anche qui è quasi ovvio, la condizione i <= j sostituisce la precedente i >= j (con la condizione = specifichiamo che va disegnata anche la diagonale).

Esercizio 5 – disegnare un triangolo BRT

print("BRT")
for i in range(N):
    for j in range(N):
        if j >= N - 1 - i:
            print("*"),
        else:
            print(" "),
    print(" ")  # a capo

Anche qui basta sostituire la condizione j = N - 1 - i con la relazione >=, a partire dall’esercizio 2.

Esercizio 6 – disegnare un triangolo TLT

print("TLT")
for i in range(N):
    for j in range(N):
        if j <= N - 1 - i:
            print("*"),
        else:
            print(" "),
    print(" ")

Ormai avete capito la regola, non serve spaccarsi la testa.

I pattern generati da questi programmi sono riportati in alto, all’inizio dell’articolo, nello stesso ordine.

Ok, abbiamo finito.! Con la prossima e ultima parte disegneremo frecce.

Altri articoli del blog

Vi lascio anche i riferimenti per le altre puntate:

Link utili Python