Showing posts with label projects. Show all posts
Showing posts with label projects. Show all posts

Wednesday, July 17, 2013

Bagarino: what is it good for?

Tickets Have I ever told you about bagarino, a ticketing system I created?
Last time I wrote some code for it I added multi-CPU support to its existing nodejs-, expressjs-powered core.
It uses Redis as its backend store and sports some simple Javascript code I wrote during a few sleepless nights.

But, "what is it good for?"
Well, let's pretend you want to grant, secure and govern access to a certain content one of your users rented/bought/subscribed-to/won on your system (e.g. a game item, or a picture, an illustration, a book or even an entire movie hosted on a CDN).

You may need to establish how many times (or how long) that good can be accessed by that user.
You may also need to enforce these rules in a simple, predictable manner.

Unique, alphanumerical, tickets that "mark" your content come to the rescue.
And bagarino allows you to manage them using different policies that establish when exactly a ticket expires.
Some of these policies are as simple as time-based counters. Some of them are a bit more complicated (but not too much, don't worry).

Give it a try and let me know.

... By the way, after "what is it good for?" I hope you didn't jump right to the "absolutely nothing" line ;-)


Photo courtesy of Sam Howzit

Monday, August 31, 2009

How to save an XML file in Java and Eclipse

One problem I faced today was saving the content of an XML document (org.w3c.dom.Document) to a newly created file.
The file I was outputting to was an Eclipse abstraction (precisely org.eclipse.core.resources.IFile) of a regular one and the method offered by this IFile for setting its contents is "IFile.setContents(InputStream source, boolean force, boolean keepHistory, IProgressMonitor monitor)".
I needed to bridge the gap between that org.w3c.dom.Document and the InputStream required by "IFile.setContents()", and here's the way I did it:
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

try
{
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer();

transformer.setOutputProperty(OutputKeys.METHOD, "xml");
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");

PrintWriter writer =
new PrintWriter(outputStream);

transformer.transform(new DOMSource(document),
new XMLWriter(writer).toXMLResult());

writer.flush();
}
catch (TransformerConfigurationException exc)
{
// DEBUG
exc.printStackTrace();
}
catch (TransformerException exc)
{
// DEBUG
exc.printStackTrace();
}
InputStream source = new ByteArrayInputStream(outputStream.toByteArray());

The main classes being used here are from package "javax.xml.transform", with the method "Transformer.transform(javax.xml.transform.dom.Source source, Result result)" basically taking care of all the stuff.

I'm going to package this one into a library called "LifeSavingUtilities"...

Wednesday, February 13, 2008

Overcome fear

Have you ever wondered about importing the Voice XML Schema (see http://www.w3.org/TR/voicexml21/) into an Eclipse EMF model? Well, I have, and the result was a bunch of really annoying errors that came out after about 3 minutes of CPU intense work.

Errors I wasn't prepared to. Just for being sure of what my eyes saw I validated the VXML XSD file (using XSV)... no errors found... mmmmhhh...

What to do next? Two options:
  • find why the Eclipse XML parser (I suspect it is Xerces) isn't working and fix it (I can only imagine the divine punishment I deserved by only thinking of it...) or try to adjust the XML Schema to avoid the errors (if you wanna give it a try I warn you that XML Schema is very hard not only to write but just to understand);
  • google the web to find a Good Samaritan who already solved this

You know? Only one person can solve this. His name is Tim Myer and I want to thank him for his really helpful post. Thank you Tim!

And you folks, whatareyouwaitingfor?!?! Go check Tim's post to make out of this dreadful situation and easily overcome your fear!

Tuesday, January 8, 2008

An approach to scheduling policies handling and implementation in FreeRTOS

Introduction

The FreeRTOS scheduler is something slightly different from the common concept of "scheduler" people are used to when talking about Operating Systems.
FreeRTOS does indeed provide a scheduling mechanism, not a scheduling policy (C'mon... Round-robin running fixed-priority tasks can't be truly considered a scheduling policy... Can't it?).

1. Possible solutions

Thus the FreeRTOS system lacks a convenient scheduling policy and a convenient way to effortlessly provide it to task developers.
Essentially there are three possible solutions:
  • Hard-coding policies within the FreeRTOS scheduling mechanism
  • Collaborative scheduling
  • Enhanced collaborative scheduling

1.1 Hard-coding policies within the FreeRTOS scheduling mechanism

It essentially means modifying the code which manages context-switches by implementing into this very code the desired scheduling policy.
It is a very comfortable solution, simple and effective, but violates a good software design principle: a neat separation should be kept between mechanisms and policies. Finally, it implies modifying critical portions of the system, potentially introducing very annoying bugs.
These considerations probably make it the worst possible solution among the ones proposed here.

1.2 Collaborative scheduling

Relying on collaborative scheduling (that is: let tasks self-administrate themselves) is another possible choice: tasks share all the same priority and mutually leave the CPU to other ones by calling "taskYELD()". This way tasks are scheduled in a round-robin fashion and each one of them runs for an amount of time decided by the running task itself. This one is kind of an elegant and simple solution, but it lacks in flexibility and, above all, in a real-time environment preemptive scheduling is close to be an unavoidable choice. Least but not last, it often implies each task being aware of the other tasks needs, "intentions" and timings: but such a behavior breaks another very desirable principle: concurrent processes must be kept "isolated".

1.3 Enhanced collaborative scheduling

Probably, the best possible solution is to find a way to build a "Scheduler" task upon the primitives already provided by FreeRTOS, while relying on the preemptive scheduling mechanism it already provides. This approach is the most attractive and elegant one, but it's not simple to think of a way to implement it.

Let's start looking at what primitives and mechanisms FreeRTOS provides.
FreeRTOS has a built-in mechanism for controlling tasks (i.e. them can be suspended, delayed and resumed from an Interrupt Service Request or from an event) and it also provides primitives such as "SetPriority()" and "GetPriority()" for managing the priority of a task.
The fact is we get caught in a sort of deadlock when using these last ones to achieve our objective, as shown from the following example.

Let we have three tasks, aTask, myTask and scheduler. The latter is obviously the scheduler of the system (and it's likely to schedule the other two tasks).

A solution would be to set the highest priority (say "4") for the scheduler and a lower priority for the other tasks (let it be "2"); but by doing so we prevent aTask and myTask by running at all because the scheduling mechanism of FreeRTOS at the moment of the context-switch always chooses the highest priority task.

Well: let's try to play with SetPriority() and GetPriority(): the first time the scheduler gets executed it holds the highest priority; to permit e.g. aTask to run it downgrades its own priority (of the scheduler) and the one of myTask.
But this way, unless aTask calls SetPriority() to boost the scheduler priority before a context-switch occurs, the scheduler and myTask won't have any chance to be executed anymore because of their lower priority.

So a real solution would be to use, instead of the pair Set/GetPriority(), another primitive: taskDELAY() (or, even better, taskDELAY_UNTIL()).
By doing so the algorithm changes as follows: the highest priority task is our scheduler again. When it gets executed it enforces a certain policy (e.g. EDF) by adjusting tasks priorities. Once it has finished its job it just delays its execution of a certain amount of time by calling taskDELAY_UNTIL().
Being the highest priority task, the scheduler it's scheduled immediately once it finishes its delay period (for the sake of precision the scheduler must also wait until a context-switch happens and, because of that, things should be arranged to avoid losing the predictability of the system that assures the hard real-timeness).
During the time the scheduler is sleeping the other, lower-priority, tasks gets executed according to their priority.

Obviously, by using this approach an important effort must be spent in making the amount of processing time used by the scheduler shorter as possible, too.

Although this approach can be considered a particular kind of collaborative scheduling it leaves tasks completely unaware of the policy being applied itself and, best of all, a task isn't required to know nothing nor about other tasks nor about the scheduler (which is, in fact, a task itself).
From a certain point of view, the most attractive feature of this algorithm is the tasks are required to embed no code at all to support it.

Notice how no particular constraints are posed on the policy being chosen, permitting a high degree of freedom to implement in the scheduler whatever we need, without of the tasks becoming aware of that.
This also means this algorithm provides a great flexibility, as explained in the following chapter.

2. Advanced aspects

Three advanced behaviors could be added to our scheme:
  • Dynamic scheduler delay period estimation
  • Multiple-levels schedulers
  • Multiple-policies schedulers

2.1 Dynamic scheduler delay period estimation

With a little effort a powerful feature can be provided to our algorithm: every time the scheduler gets executed it could collect some informations about the tasks and how they are behaving and it may consequently decide different lengths for its delay period to last, resulting in a greatly flexible policy which can try to reserve the highest possible CPU time to the tasks without loosing the advantages of our algorithm.

2.2 Multiple-levels schedulers

Another way of taking advantage of the flexibility of the algorithm is to create a system of multiple schedulers, each one of them acting at a different priority level and managing a group of tasks plus the scheduler of the lower priority level, in a pyramidal partitioning of the tasks.
By performing this partitioning the system could manage e.g. two different groups of tasks, each one of them performing different kind of jobs: one of them could be dedicated to Digital Signal Processing (DSP) and the other could manage all the activities involved in a cell-phone call (which includes DSP operations).

2.3 Multiple-policies schedulers

Multiple-levels schedulers perform a vertical partitioning1 of the scheduling operations, but a "horizontal" partitioning could be adopted as well.

It's the case of a system where more than one scheduler exist, each one of them enforcing a different policy semi-independently from the other schedulers.

Semi-independence is due to the fact that schedulers should avoid as much as possible to reciprocally interfere.

This scheme it's suitable for being used e.g. in a multi-CPU environment when task migration among the CPUs can occur; in such a situation two schedulers can be realised: one of them will manage tasks in a local context and the other one will interact with the other systems of the environment for establishing which task should be migrated and when.


NOTES:
  1. 1 The statement "multiple-levels schedulers perform a vertical partitioning" isn't completely true. In paragraph 2.2 DSP is not "under" other general activities that are performed during a cell-phone call, but is instead part of them. So partitioning should be considered both horizontal and vertical, not only vertical.

Tuesday, December 18, 2007

TMIG project: front-page illustration

TMIG project front-page turned out to be quite inspiring.
I think the good design of the red graphic element is the main reason for such a plenty of different versions I came to:

The one above has been the first to be printed... good, but after a while I found myself disappointed by its lack for minimalism. Well, I do find it minimal... but not enough!
So a new version made to light:


Especially for this last one I came to three different solutions (that I don't insert here to avoid an intoxication to you): one without the grey box (click and zoom the image if you don't see it), one with simply my name added and others with different reciprocal positions for the text and the graphic element.

Do you wanna see more? Are you really sure you want to? Post in the comments and I'll upload other solutions I came to.

Monday, December 17, 2007

PDF Whitepaper: "TMIG: Task MIGration library for a multi-CPU, FreeRTOS-based environment"

A new whitepaper made to the light in these cold, rainy days here in Cagliari.

It illustrates design, usage and internals of a C library I'm working on from some months. The "TMIG" library is intended for embedded, multi-CPU environments, based on the FreeRTOS operating system.
I implemented it on a Xilinx Virtex II Pro FPGA, programmed with a 3-CPUs architecture.
CPUs are three Xilinx Microblazes and the memory architecture comprises one private memory for each CPU and a large shared DDR.

I'm considering the possibility of releasing the code in a not so far future (maybe the third quarter of the 2008). If it get released a dual-license style may be chosen (GPLv2/CC/Apache + Commercial).

The TMIG project is part of the Embedded Software Lab, an on-going effort of the Computer Science Department of the University Of Cagliari.


More about the TMIG library and other FreeRTOS-related projects coming soon.
The whitepaper itself is released with the traditional CreativeCommons BY-NC-SA 3.0 license.

Sunday, November 4, 2007

PDF whitepaper: "Tecniche di 'boxing' e 'schermatura' per basi di dati SQL Server 2005"

Il PDF di questo whitepaper è disponibile a questo indirizzo.

Tecniche di "boxing" e "schermatura" per basi di dati SQL Server 2005

Nicola Orritos

Abstract

In contesti aziendali complessi ci si trova spesso di fronte a situazioni nelle quali i contenuti di una sola base di dati diventano una risorsa centrale e vitale per buona parte dell'infrastruttura IT dell'intero sistema (sia esso una grossa compagnia o un'organizzazione governativa).
Tale base di dati diventa un hub al quale devono poter accedere un gran numero di sistemi informativi implementati nelle più disparate tecnologie.

Inoltre queste stesse situazioni richiedono sempre più spesso che l'accesso a quegli stessi dati possa essere continuo e il più possibile performante (essendo presenti nell'infrastruttura alcuni sotto-sistemi che eseguono elaborazioni in real-time su di essi).
Una simile mole di richieste deve poter essere accuratamente gestita e controllata, onde evitare dispersioni dei dati, inconsistenze e utilizzi impropri degli stessi. Si ha cioè bisogno di uno strato di intermediazione tra le informazioni contenute nei database e chiunque ne faccia richiesta per qualsiasi motivo.

Questo documento intende esporre alcune delle possibili soluzioni che è possibile adottare per raggiungere tale scopo.
L'esposizione partirà da un'analisi dei vincoli imposti dal dover soddisfare tanti sistemi diversi e prenderà in considerazione un caso particolare nel quale alcune tecnologie pre-esistenti hanno posto dei seri vincoli al'operazione di ristrutturazione intrapresa.

1. La situazione di partenza

Il sistema sul quale si interverrà presenta una classica architettura "client-server", con un'unica base di dati che serve più agenti esterni, ciascuno dei quali ha la necessità di accedere a uno o più insiemi di dati, tutti ugualmente contenuti all'interno di un'unica istanza di un DBMS SqlServer 2005. Gli agenti esterni sono alcuni sistemi informativi appartenenti all'infrastruttura IT di un'unica azienda. Alcuni di loro sono realizzati con tecnologie "compatibili" con la base di dati, altri presentano invece dei problemi di compatibilità che hanno ristretto il numero delle soluzioni applicabili (i vincoli rappresentati da queste incompatibilità saranno analizzati nel paragrafo n.3 , "Requisiti e vincoli").

I dati contenuti nella base di dati (da ora indicata con l'acronimo "DB") devono essere costantemente disponibili ai molti agenti esterni e sarebbe desiderabile se gli accessi potessero avvenire con una certa velocità.
Queste necessità portano però con loro alcune conseguenze potenzialmente molto dannose: spesso e volentieri infatti si tende a varcare il confine che separa un accesso ubiquo ai dati da un loro utilizzo indiscriminato.
Tutto questo quando invece occorrerebbe mantenere i meccanismi e le politiche di accesso i più "semplici" ed efficienti possibili, schermando allo stesso tempo il DB da comportamenti dannosi quali possono essere la proliferazione indiscriminata di utenti, tabelle, viste e permessi.

Inoltre il problema sta non solo nei dati, ma investe anche gli schemi della base di dati e altri aspetti della struttura stessa dei dati: nel caso particolare qui analizzato, prima che ci si rendesse conto delle potenziali ricadute negative della cosa, molti cosiddetti "power-users" ritenuti meritevoli di un accesso poco limitato al sistema hanno dato vita a un variegato insieme di nuove tabelle, viste, Stored Procedure e utenti che costringevano la macchina ospitante il DB a un carico di lavoro a dir poco allarmante.

Un'ulteriore aggravante è costituita dal fatto che queste problematiche hanno un potenziale dannoso che tende a non poter essere controllato con sistemi tradizionali quali l'utilizzo degli "schema" e altre tipologie "classiche" di restrizione dei permessi.
Questo è in parte anche causato dal fatto che SQL Server 2005 utilizza un modello di sicurezza e di controllo degli accessi a dir poco complicato; ben più complicato di quanto potrebbe e dovrebbe essere per poter essere gestito agevolmente da un solo DBA.

2. Requisiti e vincoli

I vincoli ai quali dovrà sottostare la soluzione in grado di ovviare a tutti questi problemi sono molteplici e quasi tutti derivano dall'elevata mole di sistemi che accedono ai dati e dalle diverse modalità con cui ciascuno di essi lo fa.
Innanzitutto dovrà essere garantita un'implementazione semplice: saranno pertanto da evitare approcci che richiedono un eccessivo numero di passaggi da svolgere da parte dei sistemi esterni al DB centrale, così come architetture particolarmente cervellotiche o composte da troppi sistemi che debbano coordinarsi tra loro.

Una cosa importantissima è garantire l'univocità e la consistenza dei dati: nessuna replicazione o distribuzione degli stessi su più DB, a meno che la cosa non possa essere resa trasparente sia a livello di API esposte sia a livello "transazionale" (nel senso relazionale del "termine").

Un altro requisito fondamentale è poi cercare di rendere il passaggio dall'attuale situazione alla nuova il più "indolore" possibile per i sistemi coinvolti: questo significa mantenere il più possibile inalterate le modalità con cui ogni sistema accede al DB; a titolo esemplificativo valga la considerazione che se un sistema accede attualmente tramite una query T-SQLruntime SQL Server, sarebbe auspicabile che non debba in futuro adattarsi ad accedere tramite Web-Service, librerie dati o altre tecnologie diverse da quella già utilizzata.
Ciò è specialmente vero per quegli agenti esterni che basano il loro accesso su una particolare strategia tecnologica in quanto l'unica applicabile per interfacciarsi a SQL Server.

Nel caso reale seguito tutto ciò va a essere ulteriormente complicato dal fatto che dovrà essere garantito ad ogni costo l'uptime del DB, sia dalla soluzione stessa una volta che ne sia stato completato il deployment, sia durante tutta la fase di transizione ad essa.

Infine, il tutto dovrà essere realizzato parallelamente a un altro importantissimo progetto. Si tratta di un'architettura fisica che assicuri al DB centrale alcuni requisiti fondamentali che attualmente non sono ancora stati implementati, in particolare un failovering piuttosto robusto affidato a un cluster di più server (operazione attualmente già oggetto di un ulteriore studio che potrebbe anch'esso essere pubblicato).


3. Premesse a un'efficace soluzione del problema

Sia ben chiaro fin d'ora che non è possibile adempiere a quanto finora esposto senza una intensa collaborazione da parte di tutti i sistemi che accedono e sfruttano la base di dati centrale.
È cioè bene affermare sin da subito che un sistema che voglia accedere ai dati una volta che essi saranno "migrati" alla nuova soluzione non potrà limitarsi a semplici modifiche di alcune delle sue query.
La collaborazione non è infatti richiesta solo a ciascuno di questi sistemi in se, ma anche e soprattutto a coloro i quali di essi fanno utilizzo: saranno queste persone a dover fornire dettagliate descrizioni dei dati ai quali solitamente accedono (o vorrebbero accedere), dei legami tra i dati che intendono estrapolare dai DB, dei formati che si aspettano di ricevere dalle loro query e di tutti quei particolari che saranno poi necessari a fornire a tutti l'accesso più veloce e completo possibile.

Tali sistemi e le persone che ne gestiscono l'accesso al DB centrale saranno cioè parte integrante della soluzione; anzi, a voler essere più precisi, essi e la loro collaborazione saranno la fetta più consistente di essa.

Parte della documentazione che si intende ricavare da questa collaborazione potrà essere estrapolata dalle query e dai dati che già sono stati implementati sulla base di dati e per alcuni di essi sarà probabilmente sufficiente limitarsi a un simile approccio.
Per gli altri casi sarà invece utile (quando non indispensabile) se si potesse procedere alla compilazione da parte dei responsabili dei sistemi coinvolti nell'operazione di una sorta di "questionari" per l'identificazione dei requisiti che si credono necessari per un proficuo utilizzo del DB da parte del software di loro competenza.
Ancor meglio sarebbe organizzare una serie di briefing che possano adempiere a tale compito.


4. Descrizione di alcune delle soluzioni possibili

4.1 Schema generale della soluzione

L'idea generale che si intende perseguire è quella di effettuare un "boxing" dei dati in una struttura software o fisica (o entrambi), che consentano una "schermatura" dei dati stessi dalle influenze esterne.
Si tratta cioè di realizzare una membrana che faccia da mediatore nello scambi di dati occorrente tra il DB centrale e gli agenti esterni che adesso accedono.
Una simile membrana dovrà essere abbastanza intelligente e flessibile da consentire un accesso personalizzato per ogni agente esterno, cercando quanto più possibile di slegarsi dalla tecnologia con cui quest'ultimo si interfaccerà ai dati.
Volendo utilizzare un termine univoco e consistente per riferirsi a questa membrana si farà d'ora in poi uso del sostantivo "Sandbox".

Nonostante le soluzioni presentate differiscano a volte anche pesantemente l'una dall'altra, è possibile individuare tra di esse uno schema comune.
Questo elemento comune è appunto la Sandbox poc'anzi introdotta: un layer di intermediazione tra i dati e l'ecosistema esterno che sarà più o meno visibile alle applicazioni, a seconda dei requisiti di manipolazione dei dati di ciascuna di esse.
Questa "visibilità" discriminatoria ha principalmente la sua ragion d'essere nei requisiti precedentemente elencati: trasparenza e tendenza alla conservazione delle attuali modalità di interfacciamento dei sistemi esterni.

Comunque, quale che sia il modo in cui ciascun sistema esterno "vede" la base di dati, alcuni dei compiti della Sandbox sono stati fissati dal committente del progetto e hanno ovviamente imposto di considerare solo quelle soluzioni che permettevano un'aderenza totale ad essi.
Di seguito l'elenco di questi compiti:
  • supporto all'autenticazione per poter utilizzare i dati
  • logging estensivo delle attività svolte (soprattutto da "chi" esse sono state svolte, quando e in quanto tempo)
  • ottimizzazione spinta delle query eseguite (in modo da non gravare eccessivamente la/e macchina/e ospitante/i il DB)
  • report periodico (a mezzo e-mail) di eventuali malfunzionamenti e di un riassunto delle attività svolte

Un'ultima importantissima funzione integrata nella Sandbox sarà quella di fornire un'interfaccia di programmazione omogenea, ad alto livello e consistente, utilizzabile per creare librerie di accesso personalizzate al DB, secondo i protocolli imposti dalla Sandbox stessa.
Tale interfaccia sarà costituita da API la cui invocazione potrà avvenire sia attraverso script T-SQL sia via codice .NET (C# o VB.NET).

La realizzazione di quest'ultima funzionalità implica a sua volta la creazione di apposite "naming conventions" e di alcune librerie "helper" che aiutino gli utenti dei sistemi esterni a crearsi le proprie routines di accesso ai dati (o ad adattare quelle preesistenti). Tali librerie di supporto saranno parte integrante della Sandbox.

Le convenzioni e gli helpers manterranno essi stessi le modalità di accesso ai dati entro determinati "confini" decisi dagli amministratori del DB centrale.
Confini che dovranno poter essere "spostati" a run-time ricorrendo a un adeguato sistema di configurazione che dovrà perciò essere veloce oltre che omogeneo e di facile comprensione.

In questo strato di API confluirebbe infine tutto lo studio realizzato in collaborazione con i gestori dei vari sistemi esterni, portando cioè a frutto la collaborazione descritta nel paragrafo "3. Premesse a un'efficace soluzione del problema".

(Si noti come alcuni requisiti, ci si riferisce ai punti fissi imposti dal committente, non siano presenti nel paragrafo "2. Requisiti e vincoli" in quanto essi partecipano attivamente e profondamente alla definizione di un particolare schema nella soluzione in via di elaborazione)


4.2 Soluzione n.1: Strato di Web Services

Si tratta della prima e più semplice soluzione che è stata esaminata: semplice, elegante, riutilizzabile e ben supportata sia dalla tecnologia .NET, sia dalle librerie che già sono state scritte (in progetti precedenti) per il DB.

Essa presenta però un serio handicap: costringerebbe chi attualmente accede ai dati tramite query sottoposte direttamente al DB a riscrivere completamente la propria strategia di interfacciamento. Inoltre non tutti i linguaggi e le tecnologie hanno un supporto completo ed efficace agli WebServices.

Si notino comunque due cose che questa soluzione è in parte già stata implementata in almeno un caso particolare: infatti attualmente viene già garantito l'interfacciamento tramite Web Services tra il DB centrale e almeno altri due sistemi dell'ecosistema IT aziendale.
Una seconda nota va poi spesa per affermare come realizzare una soluzione mista (che comprenda quindi anche la tecnologia degli Web Services) sarebbe anch'essa una possibilità sulla quale val la pena contare (a questo proposito si veda il paragrafo "4.6 Pro e contro di un approccio misto").


4.3 Soluzione n.2: Stored Procedures in codice .NET

Piccola premessa: è stata dimostrato anche nel corso di passate collaborazioni con lo stesso committente che scrivere Stored Procedures per il DBMS SQL Server 2005 utilizzando la piattaforma .NET (e il linguaggio C# in particolare) è sufficientemente performante e "sicuro" (pur se non semplicissimo).

Partendo da questo presupposto è naturale ipotizzare uno scenario nel quale l'interfacciamento al DB centrale avvenga continuando ad accedere direttamente al DB, ma non andando più a operare sulle tabelle, bensì su Stored Procedures che ne astraggano dati e semantica, preferibilmente a un livello più alto.
All'atto pratico questo significa che quegli agenti esterni che già utilizzano SQL per accedere ai dati possono continuare a farlo in relativa tranquillità.

Un simile intervento dovrebbe contemplare adeguate convenzioni e verrebbe completato realizzando un modello di programmazione T-SQL e .NET per chi volesse realizzare nuove Stored Procedures: questo adempierebbe perfettamente a quanto descritto nella seconda metà del paragrafo "4.1 Schema generale della soluzione".

La realizzazione di questo modello implica la creazione di un tutorial indipendente dalla tecnologia (perché basato sul linguaggio SQL) e di appositi files di progetto, mirati invece per un utilizzo tramite Visual Studio .NET.
Il tutto guiderebbe all'estensione delle Stored Procedures di base, che saranno comunque già fornite dall'implementazione della soluzione stessa.

Come già detto, quest'approccio garantirebbe il mantenimento della modalità di accesso "diretta" al DB che già molti sistemi adottano: chi già accede in questo modo al DB si potrebbe infatti semplicemente limitare ad aggiornare le proprie query affinché puntino alle opportune Stored Procedures, piuttosto che alle tabelle (alle quali verrebbe tra l'altro precluso l'accesso, di fatto "schermando" l'universo tabellare dagli accessi esterni attraverso lo strato di Stored Procedures).

Inoltre scrivere le Stored Procedures in codice .NET significa che esse potranno svolgere compiti molto più evoluti di quelli permessi dal solo T-SQL: controllo degli accessi e logging fra tutti (adempiendo così ai requisiti elencati nei paragrafi precedenti).

Quasi superfluo aggiungere che combinare questa soluzione con quella che fa uso di Web Services è, oltre che possibile, anche una buona politica: i sistemi che non potessero realizzare librerie di accesso personalizzate in .NET o altri che avrebbero difficoltà ad utilizzare T-SQL potrebbero dialogare con uno o più Web Service appositi.


4.4 Soluzione n.3: Viste modificabili + Stored Procedures

In realtà quella descritta in questo paragrafo è nient'altro che una possibile estensione della precedente (Soluzione n.2): l'accesso non avverrebbe più tramite Stored Procedures, ma tramite "tabelle fittizie" che schermerebbero quelle reali dalla manipolazione diretta da parte dei sistemi esterni.
Le tabelle fittizie possono essere agevolmente realizzate combinando viste, triggers e Stored Procedures: si verrebbero così a creare delle viste modificabili che, reagirebbero a un tentativo di modifica scatenando un trigger che a sua volta invocherebbe apposite Stored Procedures. Si ricadrebbe insomma nella soluzione precedente, ma presentando agli agenti esterni uno schema dei dati ancora più vicino a quello attualmente da loro utilizzato.

Schema che sarebbe inoltre più "ricco" e completo, essendo le viste in questo senso più potenti e più semplici da capire delle Stored Procedures. Questo è un vantaggio che occorre però bilanciare con una maggiore complessità rispetto a quella del modello implementato dalla Soluzione n.2.
Ed è bene far notare come una maggiore complessità porti con se un maggior numero di errori e maggiori costi di manutenzione.


4.5 Soluzione n.4: Macchine "fantasma" + mirroring

Una strada che finora non è stata ancora considerata è quella di una Sandbox "fisica" (piuttosto che software). Per "Sandbox fisica" si intende dividere fisicamente i dati "puri" dalle informazioni che i sistemi esterni vorrebbero ricavare da essi.
Un'esigenza che nasce dal fatto che, nel contesto aziendale che ha richiesto la realizzazione di questo studio, era purtroppo diventata prassi comune realizzare tabelle per raccogliere e aggregare i dati originali in nuove forme; tabelle il cui proliferare indiscriminato genera inconsistenze, ridondanza, pesantezza nell'elaborazione e numerosi problemi di sicurezza.

Questa soluzione vorrebbe "confinare" queste grosse incongruenze a una macchina che non conserva i dati reali ma solo un loro "mirror" preso dal vero DB principale, il quale resterà invece nascosto (un "fantasma") a qualsiasi modifica.
Apposite Stored Procedures o una semplice procedura di mirroring provvederanno alla sincronizzazione delle sole tabelle presenti nel DB "fantasma" con solo i dati rilevanti della macchina esposta all'esterno.

Certo quest'approccio rappresenta senza dubbio un ulteriore livello di sicurezza, ma in se non risolve le problematiche che questo documento ha evidenziato (prima fra tutte l'eccessiva "libertà" con la quale alcuni agenti esterni possono modificare dati e schemi) e pertanto andrebbe adeguatamente integrato con una o più delle altre soluzioni elencate.


4.6 Pro e contro di un approccio misto

Unire alcune delle soluzioni su-esposte è un approccio sicuramente vincente sotto molti aspetti: risolve tutti i problemi e soddisfa tutti i requisiti, garantendo un'elevata flessibilità.
Allo stesso tempo, però, esso porta con se anche alcuni problemi nuovi e non trascurabili, dei quali la complessità è potenzialmente il più dannoso. Sarebbe pertanto opportuno tenere in considerazione l'aumento della complessità quando eventualmente si valuterà come unire le varie soluzioni.

A titolo di esempio: una soluzione come la n.3 ("Viste modificabili + Stored Procedures") è molto potente ma contempla un'architettura costituita di Viste, Triggers e Stored Procedures; ben si capisce che, rispetto alla soluzione n.2 ("Stored Procedures in codice .NET"), l'aumento della complessità è piuttosto rilevante e pericoloso.
Un pericolo che si può potenzialmente manifestare a diversi livelli: concettuale, prestazionale e in sede di manutenzione del sistema.


Conclusioni

Le soluzioni descritte in questo documento sono un primo passo che detterà il modello da seguire nella costruzione del vero e proprio "contenitore intelligente" per i dati del sistema commissionato. Il modello che si andrà a scegliere dovrà poi essere ulteriormente mediato e adattato a un gran numero di diverse esigenze che molti dei software che accedono al DB hanno: alla fine si avrà quasi certamente uno schema misto che include anche alcuni casi particolari (comunque in numero molto esiguo) e che fornirà si un'architettura di interfacciamento solida e uniforme ma anche (e soprattutto) flessibile e facilmente adattabile.

Tuesday, October 30, 2007

FreeRTOS 4.6.0 released

FreeRTOS 4.6.0 has been released (October 28 2007).

This is the changelog (between v4.5.0 and v4.6.0):
+ Changed the method used to force a context switch within an ISR for the
ARM7/9 GCC ports only. The portENTER_SWITCHING_ISR() and
portEXIT_SWITCHING_ISR() macros are no longer supported. This is to
ensure correct behaviour no matter which GCC version is used, with or
without the -fomit-frame-pointer option, and at all optimisation levels.
+ Corrected the prototype for xQueueGenericSend() within queue.h.
For the ones interested on developing for the FreeRTOS environment, I'm working on a whitepaper that shouldn't be available until January 2008.