I. Introduction

Aujourd'hui, je me suis connecté à mon compte GMail, passé quelques appels professionnels, ajouté quelques sources dans Subversion, installé quelques RMP sur ma distribution Linux… Mais pourquoi est-ce que je vous parle de ça ? Eh bien tout simplement car GMail, SVN, RPM ont un élément en commun, ils stockent certaines de leurs données dans une base Berkeley DB.

II. À propos de Berkeley DB

Berkeley DB (que nous nommerons BDB) fait partie de la famille des bases de données « clé-valeur » et est sans doute le produit de cette famille le plus utilisé au monde avec plusieurs dizaines de millions de déploiements revendiqués par l'éditeur. La première version de BDB remonte à 1986 et est la propriété d'Oracle depuis février 2006.

III. La famille de Berkeley DB

III-A. Oracle BDB Core

Cette version de Berkeley DB est écrite en C ANSI et peut être utilisée comme une bibliothèque pour accéder aux données persistées. Oracle BDB fournit de nombreuses interfaces pour différents langages de programmation (C, Perl, PHP, Python…).

III-B. Oracle BDB XML Edition

Cette version est une surcouche de BDB. Cette version XML permet de stocker et récupérer facilement des documents XML. L'utilisation de XQuery permet d'accéder aux documents XML stockés.

III-C. BDB Java Edition

Cette version de Berkeley DB, 100 % Java est une base embarquée adoptant le format de stockage clé-valeur. De plus, BDB JE est très performante et flexible. Cette base supporte les transactions, permet de stocker des objets Java en utilisant seulement quelques annotations.

IV. Les fonctionnalités-clés

Chaque membre de la famille BDB possède différentes fonctionnalités. Dans toutes les familles de BDB, nous pouvons remarquer les fonctionnalités suivantes.

Feature Set Description
Data Store (DS) 1 Writer and n reader
Concurrent Data Store (CDS) n writers and n snapshot reader
Transactional Data Store (TD) Full ACID support on top of CDS
High Availability (HA) Replication for fault tolerence. Fail over recovery support

Le tableau suivant décrit les différences entre BDB "core" et BDB JE.

  DS CDS TS HA
BDB/BDB XML X X X X
BDD JE   X X  

V. Les fonctionnalités additionnelles

Vous trouverez les fonctionnalités qui rendent BDB unique !

Fonctionnalité Bénéfice
Locking Haute concurrence
Données stockées dans le format natif de l'application Performance et pas de conversion nécessaire
API et pas de SQL Performances et flexibilité et contrôle
In Process et pas de client/serveur Performances et pas d'IPC nécessaire
Zéro administration Coût de possession faible
Transactions ACID et récupération Fiabilité et données intègres
Dual licences Open/Close source distributions
En mémoire ou sur disque Transacted caching/Persisted data store
Similar data access API Facilité de passer de BDB à BDB JE
Faible dépendance vers des bibliothèques tierces Facile à déployer et à utiliser
Bases de données de grandes capacités Virtuellement pas de limite de base de données

Et pour ce qui est BDB Java Edition, vous trouverez ses propres fonctionnalités dans le tableau ci-dessous :

Fonctionnalité Bénéfice
Fast, Indexed, B-Tree Récupération des données très rapide
Java JEE JTA et JCA Support Intégration avec les serveurs d'applications Java EE
Efficient Direct Persistence Layer Utilisation d'annotations pour stocker les graphes d'objets Java
Easy Java Collections API Manipulation transactionnelle des API de base au travers de Collections Java améliorées
Low Level Base API Travailler avec des schémas de données dynamiques
JMX Support Possibilité de monitoring

VI. Introduction à Berkeley DB Java Edition

VI-A. Installation

Tout d'abord, débutons par le commencement. Pour pouvoir utiliser BDB Java Edition, vous devez l'installer à l'adresse suivante : http://www.oracle.com/technetwork/products/berkeleydb/downloads/index.html.

L'installation de Berkeley DB est assez simple, il suffit de décompresser l'archive que vous venez de télécharger !

Le seul fichier dont vous aurez besoin pour faire fonctionner les exemples que nous verrons plus tard est le : "je-*.jar".

VI-B. Les API d'accès aux données

BDB JE fournit trois API pour accéder aux données :

  • l'API de base fournit un simple modèle clé-valeur pour stocker et récupérer les données ;
  • l'API DPL (Direct Persistence Layer) qui vous laisse persister n'importe quelle classe Java comportant un constructeur par défaut en base de données. Cette API vous permet de récupérer les données avec des fonctionnalités de recherche assez riches ;
  • la Collection API qui étend la Java Collection API avec le support de la persistance et des transactions en plus de l'accès aux données.

VI-C. L'API de base par la pratique

 
Sélectionnez
// Ouverture de la base de données et création si nécessaire
EnvironmentConfig environmentConfig = new EnvironmentConfig();
environmentConfig.setAllowCreate(true);
// Physiquement  se trouve la base
Environment environment = new Environment(new File(System.getProperty("java.io.tmpdir")), environmentConfig);
DatabaseConfig databaseConfig = new DatabaseConfig();
databaseConfig.setAllowCreate(true);
databaseConfig.setSortedDuplicates(false);
Database database = environment.openDatabase(null, "BDBJESample", databaseConfig);
// Enregistrement en base
DatabaseEntry key = new DatabaseEntry("keyValue".getBytes("UTF-8));
DatabaseEntry data = new DatabaseEntry("dataVAlue".getBytes("UTF-8));
database.put(null, key, data);
// Récupération des enregistrements
DatabaseEntry searchEntry = new DatabaseEntry();
database.get(null, key, searchEntry, LockMode.DEFAULT);
String found = new String(searchEntry.getData(),"UTF-8");
// Mise à jour de l'enregistrement
database.put(null, key, data);
// Suppression en base
database.delete(null, key);
// Fermeture de la connexion à la base
database.close();
environment.close();

Comme vous pouvez le remarquer, l'utilisation de cette API est très simple mais assez verbeuse.

VI-D. L'API DPL par la pratique

Tout d'abord, avant de commencer à vous parler de DPL, même si nous sommes dans l'univers « NoSQL », il est toujours possible de faire une analogie avec le SQL.

Terme SQL Équivalence Oracle DPL
Database Environment
Table Primary Index and its related secondary indices
Primary Index Primary Index
Secondary Index Secondary Index
Tuple/Row Entity

L'exemple que je vais vous présenter se décompose en deux parties. Premièrement, un entity bean et une classe de management qui gère le CRUD (Create-Replace-Update-Delete) au-dessus de l'entity bean.

 
Sélectionnez
@Entity
public class Employee {

    @PrimaryKey
    public Integer id;
    public String name;
    public String forname;

    @SecondaryKey(relate = Relationship.MANY_TO_MANY,
        relatedEntity = Project.class,
        onRelatedEntityDelete = DeleteAction.NULLIFY)
    public Set<Long> projects;

    public Employee(Integer id, String name, String forname, Set<Long> projects) {
        this.id = id;
        this.name = name;
        this.forname = forname;
        this.projects = projects;
    }
}

Il s'agit en effet d'un simple POJO avec quelques annotations. Ceux qui connaissent un peu JPA ne seront pas perdus !

Le code ci-dessous vous montre comment accéder aux données présentes dans le POJO Employee.

 
Sélectionnez
@Entity
EnvironmentConfig environmentConfig = new EnvironmentConfig();
environmentConfig.setAllowCreate(true);
// Physiquement  se trouve la base
Environment environment = new Environment(new File(System.getProperty("java.io.tmpdir")), environmentConfig);
StoreConfig storeConfig = new StoreConfig();
storeConfig.setAllowCreate(true);

EntityStore entityStore = new EntityStore(environment, "BDBJEDPLSample", storeConfig);
PrimaryIndex<Integer, Employee> employeePrimaryIndex = entityStore.getPrimaryIndex(Integer.class, Employee.class);
employeePrimaryIndex.putNoReturn(new Employee(12,"francois", "ostyn", null));

Employee employee = employeePrimaryIndex.get(12);
Assert.assertNotNull(employee);
employeePrimaryIndex.delete(12);
employee = employeePrimaryIndex.get(12);
Assert.assertNull(employee);

entityStore.close();
environment.close();

Dans l'exemple ci-dessus nous ne gérons ni les transactions, ni des relations complexes.

VII. Description de l'environnement de Berkeley DB Java Edition

Une base de données BDB JE est composée d'un ou plusieurs fichiers de logs qui sont situés dans le répertoire d'environnement.

Par défaut, leur taille est de 10 Mb et peut être modifiée (par exemple, augmenter la taille des logs permet de limiter le nombre d'I/O).

Image non disponible

VIII. Le support des transactions

Pour gérer les transactions avec DPL, il faut faire quelques modifications dans son code.

 
Sélectionnez
EnvironmentConfig environmentConfig = new EnvironmentConfig();
environmentConfig.setAllowCreate(true);
environmentConfig.setTransactional(true); // << gestion des transactions

TransactionConfig transactionConfig = new TransactionConfig(); // << gestion des transactions
transactionConfig.setReadCommitted(true); // << gestion des transactions
// Physiquement  se trouve la base
Environment environment = new Environment(file, environmentConfig);
StoreConfig storeConfig = new StoreConfig();
storeConfig.setAllowCreate(true);
storeConfig.setTransactional(true); // << gestion des transactions

Transaction tx = environment.getThreadTransaction(); // << gestion des transactions
environment.beginTransaction(tx, transactionConfig); // << gestion des transactions

EntityStore entityStore = new EntityStore(environment, "BDBJEDPLSample", storeConfig);

PrimaryIndex<Integer, Employee> employeePrimaryIndex = entityStore.getPrimaryIndex(Integer.class, Employee.class);

employeePrimaryIndex.putNoReturn(new Employee(12, "francois", "ostyn", null));

tx.commit();

Bien entendu, vous pouvez préciser un timeout transactionnel, ainsi que le retry policy…

IX. Monitorer une application utilisant BDB JE

Étant donné que BDB JE est totalement écrit en Java, ce dernier expose bon nombre de métriques via JMX. Pour l'activer, il faut positionner la property "-DJEMonitor=true" au démarrage de la JVM.

Image non disponible

Ceci peut être très utile pour modifier le comportement de votre application à chaud ou récupérer certaines métriques.

X. Les sources

Vous pourrez trouver les sources présentées dans les exemples sur GitHub à l'adresse suivante : https://github.com/francoisostyn/bdbJeSampleFost.

XI. Conclusion

À l'heure où l'on nous parle de bon nombre de solutions « NoSQL », Berkeley DB Java Edition est bien souvent oublié et à tort. En effet, cette version est d'une performance redoutable. Cependant, je regrette tout de même la « double licence » qui pourra freiner beaucoup de monde.

En tout cas, BDB JE est parmi mes solutions NoSQL clé-valeur !

XII. Remerciements

Cet article a été publié avec l'aimable autorisation de la société SoatSoat.

Nous tenons à remercier ClaudeLELOUP pour sa relecture orthographique attentive de cet article et Mickael Baron pour la mise au gabarit.