Developpez.com

Club des développeurs et IT pro
Plus de 4 millions de visiteurs uniques par mois

Developpez.com - 4D
X

Choisissez d'abord la catégorieensuite la rubrique :


Mirroring avec 4D 2004 (à partir de 4D 2004.3)

Date de publication : Juin 2006

Par Kent D. WILBUR (Manager of Information System, 4D Inc)
 traduit de l'anglais par Stéphanie Tirtiat (Intl Tech Support)
 

Le "mirroring" était intégré à 4D Backup dans les versions antérieures à 4D 2004. 4D Backup fut ensuite intégré dans 4D 2004 mais le mirroring n'était pas implémenté dans la première version. 4D 2004.3 propose maintenant deux nouvelles commandes qui permettent de créer un système de base miroir avec 4D Server. Cette note technique porte sur l'utilisation de ces deux commandes et explique comment configurer et installer un système de mirroring.

NDT : Les fonctionnalités permettant le mirroring ont été rajoutées en 4D 2004.2, mais certains dysfonctionnements concernant la gestion du fichier d'historique ayant été corrigés en 4D 2004.5, nous vous conseillons l'utilisation de cette dernière version.

Introduction
Qu'est-ce que le mirroring ?
La base miroir requiert-elle des conditions spéciales ?
Les fichiers d'historique
Schéma séquentiel des fichiers d'historique
Nouvelle commande "Nouveau fichier historique"
Transfert du segment du fichier d'historique
Nouvelle commande "INTEGRER FICHIER HISTORIQUE"
Gestion d'erreur
La base exemple
Créer la base miroir donnée en exemple
Les préférences du mirroring
Paramétrage des préférences du miroir
Côté serveur
Côté client
Le process du mirroring
Côté serveur principal
Côté serveur miroir
Maintenir les utilisateurs hors de la base miroir
Restauration d'urgence
Catastrophe mineure
Catastrophe majeure
La fonction Nouveau fichier historique et opérations critiques
Conclusion
Télécharger la base exemple


Introduction


Le "mirroring" était intégré à 4D Backup dans les versions antérieures à 4D 2004. 4D Backup fut ensuite intégré dans 4D 2004 mais le mirroring n'avait pas été implémenté dans la première version. 4D 2004.3 propose maintenant deux nouvelles commandes qui permettent de créer un système de base miroir avec 4D Server. Cette note technique porte sur l'utilisation de ces deux commandes et explique comment configurer et installer un système de mirroring. L'objectif de cette note technique est de vous permettre de construire une base miroir avec ces deux commandes. Elle ne cherche pas à vous donner la solution parfaite : vous devrez certainement modifier le code proposé ici pour qu'il convienne à vos besoins spécifiques. Pour montrer efficacement le principe du mirroring, j'ai dû ajouter quelques techniques intéressantes comme la création et la maintenance de fichiers de préférences au format XML, ou la modification des préférences sur le serveur depuis un 4D Client, ce qui requiert une communication adaptée en Client/Serveur.


Qu'est-ce que le mirroring ?


Le mirroring est le fait d'avoir une seconde base identique tournant en parallèle de la base de production. L'objectif est de fournir le plus rapidement possible une solution de secours dans le cas où la base de production est inaccessible ou inopérante pour quelque raison que ce soit. Le mirroring fonctionnant sur la synchronisation entre les deux bases, cette base miroir sera aussi à jour, à partir de la dernière synchronisation, que la base de production qu'elle doit seconder. Si le fichier d'historique qui contient toutes les informations depuis la dernière synchronisation avec le serveur principal est récupérable, il suffira de synchroniser les dernières données saisies pour avoir une base miroir à jour et tournant comme serveur principal. Puisque la base miroir tourne déjà elle-même en serveur, tout ce processus peut être fait rapidement en quelques minutes pour rétablir une base à nouveau opérationnelle. Pas besoin de restaurer depuis un backup. Le mirroring est le moyen le plus rapide pour mettre en place un serveur de secours comme serveur principal.


La base miroir requiert-elle des conditions spéciales ?


Avant 4D 2004, la réponse était oui. Les machines impliquées devaient être pratiquement identiques : même partition de disque dur, même système d'exploitation. Elles devaient être littéralement la copie conforme. Avec 4D 2004, ce n'est plus nécessaire. Le mirroring de 4D 2004.3 peut même s'utiliser en cross-plateforme. Le seul impératif de la machine miroir est qu'elle ne peut absolument pas modifier les données elle-même. Vous devez donc vous assurer que votre méthode lancée au démarrage ne modifie aucune donnée automatiquement et qu'aucune personne ne peut accidentellement se connecter à cette base miroir et modifier quoi que ce soit.


Les fichiers d'historique


Le coeur des deux systèmes de mirroring, celui avant 4D 2004 et l'actuel, sont les fichiers d'historiques. Pour installer une base miroir, vous faites simplement une sauvegarde de votre base en intégrant un fichier d'historique. Quittez le serveur et transférez tous les fichiers vers la machine miroir. Tous les fichiers doivent être identiques. Les deux serveurs, le principal et le miroir, sont alors relancés. La maintenance du serveur miroir se passe comme suit : périodiquement, un nouveau fichier d'historique est créé sur le serveur principal. Le fichier d'historique précédent est alors envoyé au serveur miroir où il est intégré. Ce processus prend effet indéfiniment pour maintenir une synchronisation entre les deux serveurs.


Schéma séquentiel des fichiers d'historique


Chaque sauvegarde et fichier d'historique d'un backup possède un numéro unique. Si vous avez l'habitude d'utiliser le backup de 4D Serveur, vous les reconnaîtrez facilement. Par exemple : MaBase[0739].4BK et MaBase[0738].4BL. Quand un système de mirroring est impliqué, chaque transfert d'un fichier d'historique vers la base miroir créée un nouveau segment du fichier d'historique. Pour les identifier, leur nom comporte une numérotation pour les segments :

MaBase[0739-0001].4BL ; MaBase[0739-0002].4BL ; MaBase[0739-0003].4BL ; etc.…

Ce sont ces segments qui sont envoyés à la machine miroir pour y être intégrés.


Nouvelle commande "Nouveau fichier historique"


Nouveau fichier historique

La commande Nouveau fichier historique ferme le fichier d'historique courant, le renomme, et en créé un nouveau au même endroit que le précédent. C'est le même procédé utilisé par la commande SAUVEGARDER. La différence est qu'il n'y a pas de sauvegarde, seulement un fichier d'historique. La commande Nouveau fichier historique retourne le nom complet du chemin d'accès au fichier d'historique précédent qui vient d'être fermé et renommé. Ce nom contient le numéro de la dernière sauvegarde et le numéro de segment comme décrit précédemment. La commande ne s'exécute que sur un 4D Serveur. Si elle est exécutée sur une autre application, elle retourne une erreur 1412 et ne fait rien. Elle requiert aussi la présence d'un fichier d'historique. S'il n'y en a pas, elle retourne une erreur 1413. Tous les process du 4D Serveur sont arrêtés quand la commande Nouveau fichier historique est exécutée.


Transfert du segment du fichier d'historique


Une fois qu'un segment du fichier d'historique a été créé et fermé, il est transmis au serveur miroir. La façon dont le transfert s'opère dépend du développeur. Le fichier peut être transmis manuellement ou par programmation en utilisant des volumes partagés en réseau. Avec les 4D Internet Commands, vous pouvez créer un mécanisme de transfert de fichier par FTP, puis utiliser 4D Open pour que la base miroir intègre le fichier d'historique transféré par FTP. Dans la base exemple fournie, j'ai choisi d'utiliser les web services (SOAP) pour envoyer et intégrer les fichiers parce que c'est la solution la plus simple et la plus facile pour communiquer au serveur principal le statut des opérations d'intégration de fichier dans le cas d'un bon déroulement ou d'une erreur. Les fichiers de sauvegarde et d'historique se voient donc octroyer un numéro unique par la commande SAUVEGARDER.

Rappel : MaBase[0739].4BK et MaBase[0738].4BL. La différence ici est qu'il n'y a pas de sauvegarde, seulement un nouveau fichier d'historique.


Nouvelle commande "INTEGRER FICHIER HISTORIQUE"


INTEGRER FICHIER HISTORIQUE

La commande INTEGRER FICHIER HISTORIQUE lance l'intégration du fichier passé en paramètre dans la commande. La commande ferme alors le fichier d'historique existant, lit les dernières données entrées dans le fichier d'historique et les intègre dans le fichier de données. Le fichier intégré devient alors le fichier d'historique courant de la base. Le mirroring est maintenant terminé et les deux bases de données sont synchronisées. Cependant, plusieurs problèmes peuvent être soulevés durant le processus. Tout d'abord, la commande ne fonctionne qu'avec 4D Serveur. Si ce n'est pas un 4D Serveur, elle retourne une erreur 1412 et le fichier n'est pas intégré. Ensuite, il faut qu'il y ait un fichier d'historique courant renseigné, sinon la commande retourne une erreur 1403. Ces deux problèmes peuvent être facilement résolus. Mais le plus important est la désynchronisation du fichier d'historique. Les fichiers de sauvegarde et d'historique comportent en interne des suites numériques que j'appellerai, faute de trouver un meilleur terme, vérification de séquence numérique. Pour qu'une intégration se fasse correctement, les segments des fichiers de sauvegarde et d'historique doivent comporter une séquence numérique correcte. Vous ne pouvez pas changer cette séquence en renommant les fichiers. Ces nombres sont intégrés dans la structure des fichiers eux-mêmes et assurent que le prochain fichier à intégrer est bien le "suivant" correspondant à la "sauvegarde". Si quelque chose vient perturber cette séquence numérique dans le fichier d'historique, l'intégration ne peut pas se faire et une erreur 1410 est générée qui signifie en gros "Mauvais fichier d'historique. Le fichier d'historique existe, mais ne correspond pas à la base de données en cours."


Gestion d'erreur


Pour installer et faire fonctionner correctement un système de miroir, il faut pouvoir gérer les erreurs. Des problèmes peuvent parfois apparaître. Certains sans conséquence et le mirroring continue de fonctionner selon le "scheduler". D'autres sont fatals. Peu importe l'erreur, il est essentiel de la gérer efficacement. Si vous n‘utilisez pas une procédure lancée par la commande APPELER SUR ERREUR et qu'une erreur se produit, le mirroring va s'arrêter sans avoir terminé la tâche, sans avoir rien fait ou encore sans même notifier qu'il y a eu une erreur. De plus si le process travaille avec un délai, il sera interrompu et ne se déclenchera plus. Il est donc primordial de créer et d'utiliser une routine avec APPELER SUR ERREUR quand on utilise une commande de mirroring.


La base exemple


La base donne l'exemple d'un simple système de mirroring. Il vous faudra deux serveurs 4D 2004.2 ou version ultérieure. La base contient des configurations paramétrées pour la planification du mirroring, un transfert et une intégration du fichier d'historique, une gestion d'erreur et une solution à une situation catastrophe.


Créer la base miroir donnée en exemple


Préalablement au mirroring, vous devez avoir créé des fichiers d'historique. Vous copiez ensuite la base de données sur une machine miroir. Suivez ensuite ces étapes exactement comme elles sont écrites :

1 - Lancez la base de données. (Cette base de données utilise des préférences de configuration ; elles doivent être sélectionnées quand la base est lancée pour la première fois. Pour cette base de données, choisissez la configuration « Base principale»).

2 - Lancez une sauvegarde des données. (Note : ce serait une bonne idée d'inclure le dossier des plugins dans la sauvegarde).

3 - Allez dans les préférences de sauvegarde et créer un nouveau fichier d'historique.

4 - Fermez la base de données.

5 - Copiez tout, structure, fichiers de données, sauvegardes, fichiers d'historiques, etc… sur le second serveur.

6 - Dans le dossier "Preferences", localisez le dossier Mirror et supprimez-le.

7 - Lancez la base de données miroir avec 4D Server et cette fois, choisissez la configuration « Base Miroir ». La base miroir est maintenant prête.

8 - Lancez la base principale « Base principale » avec 4D Server. Chaque fois que le miroir ne fonctionne plus, vous devez recommencer et recréer la base miroir depuis le début, en commençant par la sauvegarde du fichier de données. Un système de sélection de configuration a été développé pour cette base exemple ; vous pouvez l'utiliser ou non. Les points qui concernent ces configurations peuvent donc être ignorés.


Les préférences du mirroring


J'ai pensé qu'il était important de différencier les deux bases de données. Puisqu'on ne peut pas utiliser un fichier de données pour distinguer les bases de données, cela casserait le mirroring, j'ai opté pour la solution d'un fichier de préférences externe. C'est un simple fichier au format XML qui stocke les préférences. Pour le serveur miroir le seul paramétrage utilisé est celui qui le renseigne comme serveur Miroir. Chaque fois que le serveur miroir est recréé, supprimez simplement les préférences et choisissez l'option "Miroir" ; c'est tout ce dont la base de données miroir a besoin. D'un autre côté, le serveur principal fait tout le travail. Il a donc besoin de bien plus de paramétrages.


Pour des raisons de sécurité, la base exemple requiert la saisie du nom de la base de données miroir. J'utilise ce nom en interne pour m'assurer que la base miroir est en fonctionnement et qu'elle correspond bien à celle à laquelle vous essayez d'envoyer le log, cela avant d'appeler la fonction Nouveau fichier historique.

Je ne veux pas créer un nouveau fichier d'historique pour rien. Le second paramétrage nécessaire est l'adresse IP du serveur miroir. Si vous préférez, vous pouvez utiliser le nom de domaine retrouvé à partir d'un DNS Lookup. Ensuite, c'est la planification du mirroring, en heures et minutes. Si vous sélectionnez 00 heure et 00 minute, le mirroring du serveur s'arrêtera. Dans un système miroir, vous devez utiliser un mécanisme de planification. Peut-être voudriez-vous en utiliser un qui se déclencherait à certains moments de la journée, comme l'automatisation de la sauvegarde par le système de backup intégré à 4D Serveur. Dans ce cas, je vous laisse le construire vous-même. L'indication du dernier transfert de log est purement informative. Elle ne peut pas être modifiée. Elle donne le dernier log qui a été intégré au serveur miroir avec succès. Cette information peut aider en cas de restitution d'urgence. La partie suivante des paramètres concerne le serveur SMTP et l'adresse email où seront envoyés les messages d'erreur. Si vous laissez le paramétrage par défaut (« Aucun »), aucun message ne sera envoyé. Pour terminer, il y a un indicateur de statut du mirroring du serveur en bas de la fenêtre de dialogue. S'il n'est pas en cours de fonctionnement, vous pouvez sélectionner la boîte à cocher pour lancer le processus de mirroring sur le serveur. Il démarrera si vous avez déterminé une planification (intervalle de temps). Si le mirroring est déjà en cours il sera mis à jour avec les nouvelles valeurs.


Paramétrage des préférences du miroir


Côté serveur


Les préférences du miroir sont sauvegardées et utilisées sur le serveur. Puisque 4D crée déjà un dossier de préférences pour la sauvegarde et autres paramétrages, la base de données utilisera la même architecture pour créer ses propres préférences et les sauvegarder dans un fichier au format XML. Déterminons l'emplacement du fichier : ceci est fait en une simple méthode. Si vous souhaitez modifier l'emplacement, la chaîne trouvée ici est simplement modifiée en fonction de l'emplacement où vous voulez que soit sauvegardé le fichier. Le code convertira le chemin Windows vers Mac si nécessaire.
code 4D

Si (Faux)

` Methode: Miroir_tCheminMiroir
` Note technique : mirroring avec 4D 2004	  
` Créée par: Kent Wilbur
` Date: 9/27/2005	  
` But: Contient l'emplacement de la base miroir
¾f_Version2004x2:=Vrai
¾fK_Wilbur:=Vrai
Fin de si
 ` Declarer les parametres
C_TEXTE($0)
$0:="Preferences\\Mirror\\Settings.xml"  
`Fin de méthode

Charger/Créer le fichier des préférences : quand le 4D Serveur est lancé, le processus de mirroring tente de charger et de lire le fichier de préférences en utilisant la méthode Miroir_GestPrefsMiroir. Toutes les manipulations de ce fichier de préférences s'opèrent dans cette seule méthode récursive Miroir_GestPrefsMiroir  ; il se peut donc qu'elle soit un peu compliquée à lire au premier abord. Essayez avant tout de suivre le code dans la méthode ci-dessous, en partant du principe que le fichier et dossiers de préférences n'existent pas, en examinant la partie du Au cas ou où $tAction = "Load" (charger) - Voir page 9 -. Suivre le code pour le cas « Load» (charger) nous mènera à appeler à nouveau la méthode pour le cas « Create» (créer) ; retournez simplement en haut de la méthode et suivez maintenant ce second passage où la valeur $tAction = "Create" (créer).

Méthode : Miroir_GestPrefsMiroir
code 4D

Si (Faux)
` Note technique : mirroring avec 4D 2004
` Créée par: Kent Wilbur
` But: créer un fichier de preferences pour le miroir
` Parametres
`   $1   -   Action
¾f_Version2004x2:=Vrai
¾fK_Wilbur:=Vrai
Fin de si
` Declarer les parametres
C_TEXTE($1;$tAction)
` Declarer les variables locales
C_BOOLEEN($fAbort)
C_ALPHA(16;$sXML_Reference)
C_ALPHA(16;$sXML_ElementReference)
C_ENTIER LONG($LProcessID)
C_TEXTE($tMirror_TimeInterval)
C_TEXTE($tPreferencesPath)
C_TEXTE($tSettingsFolderPath) 
` Reassigner pour lisibilité
$tAction:=$1
` Declarer les valeurs par défaut
$fAbort:=Faux
$tPreferencesPath:=GEN_tFormatChemin (Miroir_tCheminMiroir )

Après avoir récupéré le chemin d'accès à partir de Miroir_tCheminMiroir, la méthode GEN_tFormatChemin modifie simplement le nom du chemin selon la plateforme (Macintosh ou Windows).
code 4D

Au cas ou 
: ($tAction="Create")  `créer
 		CONFIRMER("Sélectionnez le type de ce serveur.";"Base principale";"Base miroir")
 		Si (OK=1)
 			¾tMirror_ServerType:="Base principale"
 		Sinon
  			¾tMirror_ServerType:="Base miroir"
		 Fin de si 
		¾tMirror_DatabaseName:="Aucun"
		¾tMirror_ServerIPAddress:="0.0.0.0"
		$tMirror_TimeInterval:="00:00:00"
		¾tMirror_LastLogNumber:="[0000]"
		¾tMirror_SMTPServer:=¾tMirror_DatabaseName
		¾tMirror_ErrorEMailAccount:="nom.prenom@domaine.com"
		¾tMirror_AuthenticationRequired:="Non"
		¾tMirror_AuthenticationUserName:=¾tMirror_DatabaseName
		¾tMirror_AuthenticationPassword:=¾tMirror_DatabaseName
: (Nombre de parametres#1)
 		$fAbort:=Vrai  ` pas assez de parametres
Sinon
 	$tMirror_TimeInterval:=Chaine(¾hMirror_TimeInterval;h mn s )
Fin de cas
Au cas ou
: ($fAbort) 
: ($tAction="Load")  `charger
	$tSettingsFolderPath:=GEN_tCheminDossier ($tPreferencesPath)

La méthode GEN_tCheminDossier sépare le nom du chemin des dossiers du nom du fichier lui-même.
code 4D

Si (Tester chemin acces($tSettingsFolderPath)#0)  ` le dossier existe-t-il ?	
 GEN_PreparerChemin ($tSettingsFolderPath)
Fin de si

La fonction Tester chemin acces retournera 0 (zéro) si la valeur passée est un chemin de dossier. Comme nous testons si c'est un dossier, si une autre valeur est retournée, un ou plusieurs de ces dossiers n'existent pas. GEN_PreparerChemin est une méthode qui va créer tous les dossiers manquants selon le chemin retourné. Ci-dessous, nous vérifions à nouveau l'existence du fichier avec la fonction Tester chemin acces. Elle retourne 1 si la valeur passée est un fichier. En vérifiant le chemin d'accès complet, y compris le nom du fichier, si tout autre valeur que 1 est retournée, cela signifie que le fichier n'existe pas.
code 4D

Si (Tester chemin acces($tPreferencesPath)#1)  
` vérifier si un fichier valide existe

Nous appelons donc à nouveau la méthode Miroir_GestPrefsMiroir pour créer le fichier des préférences.
code 4D

Miroir_GestPrefsMiroir ("Create")  ` sinon créer un fichier de preferences

Si le fichier existe, nous chargeons simplement les paramétrages :
code 4D

		Sinon 
			$sXML_Reference:=DOM Analyser source XML($tPreferencesPath)
			$sXML_ElementReference:=DOM Chercher element XML($sXML_Reference;
                "/Mirror/PreferenceSetting/Mirror_ServerType")
			DOM LIRE VALEUR ELEMENT XML($sXML_ElementReference;<>tMirror_ServerType)
			$sXML_ElementReference:=DOM Chercher element XML($sXML_Reference;
                "/Mirror/PreferenceSetting/Mirror_ServerName")
			DOM LIRE VALEUR ELEMENT XML($sXML_ElementReference;<>tMirror_DatabaseName)
			$sXML_ElementReference:=DOM Chercher element XML($sXML_Reference;
                "/Mirror/PreferenceSetting/Mirror_ServerIPAddress")
			DOM LIRE VALEUR ELEMENT XML($sXML_ElementReference;<>tMirror_ServerIPAddress)
			$sXML_ElementReference:=DOM Chercher element XML($sXML_Reference;
                 "/Mirror/PreferenceSetting/Mirror_TimeInterval")
			DOM LIRE VALEUR ELEMENT XML($sXML_ElementReference;$tMirror_TimeInterval)
			$sXML_ElementReference:=DOM Chercher element XML($sXML_Reference;
                 "/Mirror/PreferenceSetting/Mirror_LastBackupNumber")
			DOM LIRE VALEUR ELEMENT XML($sXML_ElementReference;<>tMirror_LastLogNumber)
			$sXML_ElementReference:=DOM Chercher element XML($sXML_Reference;
                  "/Mirror/PreferenceSetting/Mirror_ErrorSMTPServer")
			DOM LIRE VALEUR ELEMENT XML($sXML_ElementReference;<>tMirror_SMTPServer)
			$sXML_ElementReference:=DOM Chercher element XML($sXML_Reference;
                  "/Mirror/PreferenceSetting/Mirror_ErrorEMail")
			DOM LIRE VALEUR ELEMENT XML($sXML_ElementReference;<>tMirror_ErrorEMailAccount)
			$sXML_ElementReference:=DOM Chercher element XML($sXML_Reference;
                  "/Mirror/PreferenceSetting/Mirror_ErrorEMailAuthentication")
			DOM LIRE VALEUR ELEMENT XML($sXML_ElementReference;<>tMirror_AuthenticationRequired)
			$sXML_ElementReference:=DOM Chercher element XML($sXML_Reference;
                  "/Mirror/PreferenceSetting/Mirror_ErrorEMailUsername")
			DOM LIRE VALEUR ELEMENT XML($sXML_ElementReference;<>tMirror_AuthenticationUserName)
			$sXML_ElementReference:=DOM Chercher element XML($sXML_Reference;
                  "/Mirror/PreferenceSetting/Mirror_ErrorEMailPassword")
			DOM LIRE VALEUR ELEMENT XML($sXML_ElementReference;<>tMirror_AuthenticationPassword)
			DOM FERMER XML($sXML_Reference)
			<>hMirror_TimeInterval:=Heure($tMirror_TimeInterval)
		Fin de si 
		
	: ($tAction="Save")  `sauvegarder
		$sXML_Reference:=DOM Analyser source XML($tPreferencesPath)
		$sXML_ElementReference:=DOM Chercher element XML($sXML_Reference;
               "/Mirror/PreferenceSetting/Mirror_ServerType")
		DOM ECRIRE VALEUR ELEMENT XML($sXML_ElementReference;<>tMirror_ServerType)
		$sXML_ElementReference:=DOM Chercher element XML($sXML_Reference;
               "/Mirror/PreferenceSetting/Mirror_ServerName")
		DOM ECRIRE VALEUR ELEMENT XML($sXML_ElementReference;<>tMirror_DatabaseName)
		$sXML_ElementReference:=DOM Chercher element XML($sXML_Reference;
               "/Mirror/PreferenceSetting/Mirror_ServerIPAddress")
		DOM ECRIRE VALEUR ELEMENT XML($sXML_ElementReference;<>tMirror_ServerIPAddress)
		$sXML_ElementReference:=DOM Chercher element XML($sXML_Reference;
               "/Mirror/PreferenceSetting/Mirror_TimeInterval")
		DOM ECRIRE VALEUR ELEMENT XML($sXML_ElementReference;$tMirror_TimeInterval)
		$sXML_ElementReference:=DOM Chercher element XML($sXML_Reference;
               "/Mirror/PreferenceSetting/Mirror_LastBackupNumber")

		DOM ECRIRE VALEUR ELEMENT XML($sXML_ElementReference;<>tMirror_LastLogNumber)
		$sXML_ElementReference:=DOM Chercher element XML($sXML_Reference;
                "/Mirror/PreferenceSetting/Mirror_ErrorSMTPServer")
		DOM ECRIRE VALEUR ELEMENT XML($sXML_ElementReference;<>tMirror_SMTPServer)
		$sXML_ElementReference:=DOM Chercher element XML($sXML_Reference;
                "/Mirror/PreferenceSetting/Mirror_ErrorEMail")
		DOM ECRIRE VALEUR ELEMENT XML($sXML_ElementReference;<>tMirror_ErrorEMailAccount)
		$sXML_ElementReference:=DOM Chercher element XML($sXML_Reference;
                 "/Mirror/PreferenceSetting/Mirror_ErrorEMailAuthentication")
		DOM ECRIRE VALEUR ELEMENT XML($sXML_ElementReference;<>tMirror_AuthenticationRequired)
		$sXML_ElementReference:=DOM Chercher element XML($sXML_Reference;
                  "/Mirror/PreferenceSetting/Mirror_ErrorEMailUsername")
		DOM ECRIRE VALEUR ELEMENT XML($sXML_ElementReference;<>tMirror_AuthenticationUserName)
		$sXML_ElementReference:=DOM Chercher element XML($sXML_Reference;
                   "/Mirror/PreferenceSetting/Mirror_ErrorEMailPassword")
		DOM ECRIRE VALEUR ELEMENT XML($sXML_ElementReference;<>tMirror_AuthenticationPassword)
		DOM EXPORTER VERS FICHIER($sXML_Reference;$tPreferencesPath)
		DOM FERMER XML($sXML_Reference)
		
	: ($tAction="SaveFromClient") | ($tAction="Save&LaunchFromClient") 
     `sauvegarde à partir du client ou sauvegarge & lancement à partir du client
		Miroir_GestPrefsMiroir ("Save")
		Au cas ou 
			: ($tAction="Save&LaunchFromClient")  ` sauvegarge & lancement à partir du client
				$LProcessID:=Nouveau process("P_MiroirProcess";32000;"MirroringProcess";*)
			Sinon 
				$LProcessID:=Chercher process("MirroringProcess";*)
				Si ($LProcessID>0)
					ENDORMIR PROCESS($LProcessID;0)  `réveille le process pour mettre à jour les paramètres
				Fin de si 
		Fin de cas 

	: ($tAction="Create")  `créer
		$sXML_Reference:=DOM Creer ref XML("Mirror")
		$tXML_ElementValue:="/Mirror/PreferenceSetting/Mirror_ServerType"
		$sXML_ElementReference:=DOM Creer element XML($sXML_Reference;$tXML_ElementValue)
		DOM ECRIRE VALEUR ELEMENT XML($sXML_ElementReference;<>tMirror_ServerType)
		$tXML_ElementValue:="/Mirror/PreferenceSetting/Mirror_ServerName"
		$sXML_ElementReference:=DOM Creer element XML($sXML_Reference;$tXML_ElementValue)
		DOM ECRIRE VALEUR ELEMENT XML($sXML_ElementReference;<>tMirror_DatabaseName)
		$tXML_ElementValue:="/Mirror/PreferenceSetting/Mirror_ServerIPAddress"
		$sXML_ElementReference:=DOM Creer element XML($sXML_Reference;$tXML_ElementValue)
		DOM ECRIRE VALEUR ELEMENT XML($sXML_ElementReference;<>tMirror_ServerIPAddress)
		$tXML_ElementValue:="/Mirror/PreferenceSetting/Mirror_TimeInterval"
		$sXML_ElementReference:=DOM Creer element XML($sXML_Reference;$tXML_ElementValue)
		DOM ECRIRE VALEUR ELEMENT XML($sXML_ElementReference;$tMirror_TimeInterval)
		$tXML_ElementValue:="/Mirror/PreferenceSetting/Mirror_LastBackupNumber"
		$sXML_ElementReference:=DOM Creer element XML($sXML_Reference;$tXML_ElementValue)
		DOM ECRIRE VALEUR ELEMENT XML($sXML_ElementReference;<>tMirror_LastLogNumber)
		$tXML_ElementValue:="/Mirror/PreferenceSetting/Mirror_ErrorSMTPServer"
		$sXML_ElementReference:=DOM Creer element XML($sXML_Reference;$tXML_ElementValue)
		DOM ECRIRE VALEUR ELEMENT XML($sXML_ElementReference;<>tMirror_SMTPServer)
		$tXML_ElementValue:="/Mirror/PreferenceSetting/Mirror_ErrorEMail"
		$sXML_ElementReference:=DOM Creer element XML($sXML_Reference;$tXML_ElementValue)
		DOM ECRIRE VALEUR ELEMENT XML($sXML_ElementReference;<>tMirror_ErrorEMailAccount)
		$tXML_ElementValue:="/Mirror/PreferenceSetting/Mirror_ErrorEMailAuthentication"
		$sXML_ElementReference:=DOM Creer element XML($sXML_Reference;$tXML_ElementValue)
		DOM ECRIRE VALEUR ELEMENT XML($sXML_ElementReference;<>tMirror_AuthenticationRequired)
		DOM EXPORTER VERS FICHIER($sXML_Reference;$tPreferencesPath)
		$tXML_ElementValue:="/Mirror/PreferenceSetting/Mirror_ErrorEMailUsername"
		$sXML_ElementReference:=DOM Creer element XML($sXML_Reference;$tXML_ElementValue)
		DOM ECRIRE VALEUR ELEMENT XML($sXML_ElementReference;<>tMirror_AuthenticationUserName)
		
		$tXML_ElementValue:="/Mirror/PreferenceSetting/Mirror_ErrorEMailPassword"
		$sXML_ElementReference:=DOM Creer element XML($sXML_Reference;$tXML_ElementValue)
		DOM ECRIRE VALEUR ELEMENT XML($sXML_ElementReference;<>tMirror_AuthenticationPassword)
		DOM EXPORTER VERS FICHIER($sXML_Reference;$tPreferencesPath)
		DOM FERMER XML($sXML_Reference)
		<>hMirror_TimeInterval:=Heure($tMirror_TimeInterval)
		Fin de cas 
  `Fin de méthode
info Si vous avez quelques soucis avec les notions de XML, vous pouvez vous pencher un peu sur le XML en cherchant, dans notre base de connaissance, les notes techniques concernant le XML. Nous utilisons la méthode DOM (Document Object Model) qui nous permet de construire une structure complète en mémoire. Une analogie très simplifiée entre les commandes DOM et les concepts de 4D vous est présentée ci-dessous :
· DOM Creer ref XML
crée une référence XML en mémoire, similaire au concept de la création d'un document 4D View en mémoire.
· DOM Creer element XML
crée une référence à un élément individuel en mémoire, similaire à un pointeur ou une variable. Mais une variable hiérarchique. Notez tous les « / » dans les valeurs d'élément.
· DOM Analyser source XML
charge entièrement la source XML en mémoire et analyse toute la structure XML en mémoire.
· DOM ECRIRE VALEUR ELEMENT XML
stocke une valeur spécifique dans un élément individuel. Pensez à cela comme si c'était $ptrVariable-> := « maValeur »
· DOM Chercher element XML
trouve un élément individuel spécifié dans la structure XML chargée en mémoire.
· DOM LIRE VALEUR ELEMENT XML
charge la valeur d'un élément individuel dans un objet 4D. Pensez à cela comme si c'était maVariable/monChamp :=$ptrVariable->
· DOM EXPORTER VERS FICHIER
écrit la totalité de la structure dans un fichier.
· DOM FERMER XML
libère la mémoire utilisée par la structure XML lue via les commandes DOM.

Le fichier qui résulte de tout cela ressemble à ceci :

<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<Mirror>
	<PreferenceSetting>   
		<Mirror_ServerType>Base principale</Mirror_ServerType>
		<Mirror_ServerName>MaBase</Mirror_ServerName>
		<Mirror_ServerIPAddress>123.456.78.90</Mirror_ServerIPAddress>
		<Mirror_TimeInterval>06:00:00</Mirror_TimeInterval>
		<Mirror_LastBackupNumber>[0000]</Mirror_LastBackupNumber>
		<Mirror_ErrorSMTPServer>smtp.4d.fr</Mirror_ErrorSMTPServer>
		<Mirror_ErrorEMail>miroir@4d.fr</Mirror_ErrorEMail>
		<Mirror_ErrorEMailAuthentication>Non</Mirror_ErrorEMailAuthentication>
		<Mirror_ErrorEMailUsername>Aucun</Mirror_ErrorEMailUsername>
		<Mirror_ErrorEMailPassword>Aucun</Mirror_ErrorEMailPassword>
	</PreferenceSetting>
</Mirror>

Plus d'informations sur la sauvegarde et la modification du fichier XML dans un chapitre suivant.


Côté client


Cela fait plusieurs années qu'il n'y a pas eu de note technique traitant du paramétrage et du contrôle du serveur depuis une machine cliente. Si vous êtes familiarisé avec cette technique, allez directement au chapitre suivant.

Le fichier de préférences XML est stocké sur la machine du 4D Serveur, dans son dossier Préférences. Ce serait compliqué de manipuler ce fichier directement depuis une machine cliente, et de modifier son contenu. Il serait également mal venu de devoir aller sur la machine cliente et d'exécuter une méthode sur le serveur (Executer sur serveur) qui afficherait un dialogue sur la machine Serveur, et ensuite courir à cette machine pour saisir les données.

Nous allons plutôt utiliser une communication interprocess pour effectuer cette tâche, à l'aide des commandes :
LIRE VARIABLE PROCESS
et
ECRIRE VARIABLE PROCESS

Pour ces deux commandes vous devez spécifier un numéro de process, le nom de la variable dans l'autre process, ainsi que la variable du process local qui reçoit ou contient la valeur courante. Si le numéro de process est négatif, cela signifie que vous vous adressez à un numéro de process sur le serveur, pas sur le client. Pour finir, nous pouvons faire un Executer sur serveur pour que le serveur mette son fichier à jour.

Tout ce dont nous avons besoin est écrit dans la méthode formulaire pour le dialogue qui permet de modifier les préférences.
code 4D

Si (Faux)
	  ` Methode formulaire: Miroir_Preferences dans la table [zDialogues]
	  ` Note technique : mirroring avec 4D 2004
	  ` Créée par: Kent Wilbur
	  ` But: gère l'interface utilisateur pour le paramétrage des préférences du miroir
	
	¾f_Version2004x2:=Vrai
	¾fK_Wilbur:=Vrai
	
Fin de si 

  ` Declarer les variables locales
C_ENTIER LONG($LApplicationType)
C_ENTIER LONG($LFormEvent)
C_ENTIER LONG($LProcessID)
C_TEXTE($tTimeIncrement)
C_TEXTE($tSettingsFullPath)

  ` Declarer les paramètres par default
$tSettingsFullPath:=Miroir_tCheminMiroir 

$LFormEvent:=Evenement formulaire
$LApplicationType:=Type application

Au cas ou 
	: ($LFormEvent=Sur chargement )
		TABLEAU TEXTE(atMirror_Authentication;2)
		atMirror_Authentication{1}:="Non"
		atMirror_Authentication{2}:="Oui"
		
		
		Au cas ou 
			: ($LApplicationType=4D Client )
				LIRE VARIABLE PROCESS(LMirrorProcessID;¾tMirror_ServerType;¾tMirror_ServerType)
				LIRE VARIABLE PROCESS(LMirrorProcessID;¾tMirror_DatabaseName;¾tMirror_DatabaseName)
				LIRE VARIABLE PROCESS(LMirrorProcessID;¾tMirror_ServerIPAddress;¾tMirror_ServerIPAddress)
				LIRE VARIABLE PROCESS(LMirrorProcessID;¾hMirror_TimeInterval;vhMirror_TimeInterval)
				LIRE VARIABLE PROCESS(LMirrorProcessID;¾tMirror_LastLogNumber;¾tMirror_LastLogNumber)
				LIRE VARIABLE PROCESS(LMirrorProcessID;¾tMirror_SMTPServer;¾tMirror_SMTPServer)
				LIRE VARIABLE PROCESS(LMirrorProcessID;¾tMirror_ErrorEMailAccount;
              ¾tMirror_ErrorEMailAccount)
				LIRE VARIABLE PROCESS(LMirrorProcessID;¾tMirror_AuthenticationRequired;
              ¾tMirror_AuthenticationRequired)
				LIRE VARIABLE PROCESS(LMirrorProcessID;¾tMirror_AuthenticationUserName;
              ¾tMirror_AuthenticationUserName)
				LIRE VARIABLE PROCESS(LMirrorProcessID;¾tMirror_AuthenticationPassword;
               ¾tMirror_AuthenticationPassword)
				
			: ($LApplicationType=4e Dimension )
				Miroir_GestPrefsMiroir ("Load")  `charger les préférences miroir
				
			Sinon 
				NE PAS VALIDER
		Fin de cas 
		
		atMirror_Authentication:=Chercher dans tableau(atMirror_Authentication;
           ¾tMirror_AuthenticationRequired)
		Si (atMirror_Authentication=2)  ` authentification requise
			CHOIX SAISISSABLE(¾tMirror_AuthenticationUserName;Vrai)
			CHOIX SAISISSABLE(¾tMirror_AuthenticationPassword;Vrai)
		Sinon 
			CHOIX SAISISSABLE(¾tMirror_AuthenticationUserName;Faux)
			CHOIX SAISISSABLE(¾tMirror_AuthenticationPassword;Faux)
		Fin de si 
		
		$tTimeIncrement:=Sous chaine(Chaine(¾hMirror_TimeInterval;h mn );1;2)
		atMirror_Hr:=Chercher dans tableau(atMirror_Hr;$tTimeIncrement)
		$tTimeIncrement:=Sous chaine(Chaine(¾hMirror_TimeInterval;h mn );4;2)
		atMirror_Min:=Chercher dans tableau(atMirror_Min;$tTimeIncrement)
		
		  `définir les valeurs par défaut du dialogue
		Mirror_ckLaunchProcess:=0
		Au cas ou 
			: (¾tMirror_ServerType="Mirror")
				CHOIX VISIBLE(Mirror_ckLaunchProcess;Faux)
				CHOIX VISIBLE(*;"MirrorStatus";Vrai)
				tMessage:="Ce serveur tourne en tant que serveur miroir"
				
			: (Type application#4D Client )
				CHOIX VISIBLE(Mirror_ckLaunchProcess;Faux)
				CHOIX VISIBLE(*;"MirrorStatus";Vrai)
				tMessage:="Le miroir ne peut pas s'effectuer sur un 4D Mono"
				
			: (LMirrorProcessID=-1)  ` Il n'y a pas de process miroir tournant sur le serveur 
				CHOIX VISIBLE(Mirror_ckLaunchProcess;Vrai)
				CHOIX VISIBLE(*;"MirrorStatus";Faux)
				tMessage:=""
			Sinon 
				CHOIX VISIBLE(Mirror_ckLaunchProcess;Faux)
				CHOIX VISIBLE(*;"MirrorStatus";Vrai)
				tMessage:="Le miroir tourne sur ce serveur"
		Fin de cas 
		
		
	: ($LFormEvent=Sur libération )
		TABLEAU TEXTE(atMirror_Authentication;0)
		
		Si (bOK=1)
			Au cas ou 
				: ($LApplicationType=4D Client )
					ECRIRE VARIABLE PROCESS(LMirrorProcessID;¾tMirror_DatabaseName;
                   ¾tMirror_DatabaseName)
					ECRIRE VARIABLE PROCESS(LMirrorProcessID;¾tMirror_ServerIPAddress;
                   ¾tMirror_ServerIPAddress)
					ECRIRE VARIABLE PROCESS(LMirrorProcessID;¾hMirror_TimeInterval;¾hMirror_TimeInterval)
					ECRIRE VARIABLE PROCESS(LMirrorProcessID;¾tMirror_SMTPServer;¾tMirror_SMTPServer)
					ECRIRE VARIABLE PROCESS(LMirrorProcessID;¾tMirror_ErrorEMailAccount;
                    ¾tMirror_ErrorEMailAccount)
					ECRIRE VARIABLE PROCESS(LMirrorProcessID;¾tMirror_AuthenticationRequired;
                    ¾tMirror_AuthenticationRequired)
					ECRIRE VARIABLE PROCESS(LMirrorProcessID;¾tMirror_AuthenticationUserName;
                    ¾tMirror_AuthenticationUserName)
					ECRIRE VARIABLE PROCESS(LMirrorProcessID;¾tMirror_AuthenticationPassword;
                    ¾tMirror_AuthenticationPassword)
					Si (Mirror_ckLaunchProcess=1)
						$LProcessID:=Executer sur serveur("Miroir_GestPrefsMiroir";16000;"$UpdateMirrorPreferences";
                        "Save&LaunchFromClient")  `sauvegarder et lancer à partir du client
					Sinon 
						$LProcessID:=Executer sur serveur("Miroir_GestPrefsMiroir";16000;"$UpdateMirrorPreferences";
                        "SaveFromClient") 
                       `sauvegarder à partir du client
					Fin de si 
					
				: ($LApplicationType=4e Dimension )
					Miroir_GestPrefsMiroir ("Save")  `sauvegarder
			Fin de cas 
			
		Fin de si 
		
Fin de cas 

  `Fin de méthode formulaire

Le process du mirroring


Côté serveur principal


La responsabilité d'accomplissement du processus de mirroring incombe en fait au serveur principal. En effet, c'est un process en sommeil jusqu'à ce qu'il soit réveillé par la planification programmée pour créer un nouveau fichier d'historique et créer un miroir de la base. Les presque 100 % de la méthode P_MiroirProcess ne servent pratiquement qu'à simplement déterminer à quel moment le processus doit être lancé. Elle gère la modification de la planification programmée en fonction des modifications des préférences pendant la mise en veille du process. Quand le client met ses paramètres à jour, le process se réveille et recalcule à quel moment le prochain processus de mirroring doit être déclenché. Ce moment est déterminé par un mécanisme basé sur un format de date/heure (timestamp).
code 4D

Si (Faux)
	  ` Methode: P_MiroirProcess
	  ` Note technique : mirroring avec 4D 2004
	  ` Créée par: Kent Wilbur
	
	  ` But: démarre le processus du mirroring
	
	<>f_Version2004x2:=Vrai
	<>fK_Wilbur:=Vrai
	
Fin de si 

  ` Declarer les varaibles locales
C_ALPHA(6;$sVersion)
C_ENTIER LONG($LDelayTicks)
C_ENTIER LONG($LErrorCode)

C_TEXTE($tClosedLogFileName)
C_TEXTE($tDateTimeDelay)
C_TEXTE($tLogFilePath)
C_HEURE($hCurrentTime)
C_HEURE($hDelayInterval)
C_HEURE($hDelayUntil)
C_HEURE($hTimeChange)

$sVersion:=Version application
Miroir_GestPrefsMiroir ("Load")  `charger

Au cas ou 
	: (Type application#4D Server )
		ALERTE("Le Mirroring ne fonctionne qu'avec 4D Server.")
	: (Num($sVersion)<802)
		ALERTE("Le Mirroring requiert la Version 2004.2 ou ultérieure.")
	Sinon 
		Si (<>hMirror_TimeInterval#?00:00:00?)  ` Si un délai a été défini
			$hDelayInterval:=<>hMirror_TimeInterval
			$hCurrentTime:=Heure courante  ` défini maintenant pour un usage ultérieur
			Repeter 
				  ` Cette section est nécessaire parce que d'autres process peuvent appeler ce process
              `pour poursuivre. 
				  ` Mais nous ne voudrions pas que le process s'active trop tôt
				Si ($hDelayInterval<?00:15:00?)
					$hCurrentTime:=Heure courante 
              ` Moins de 15 minutes, défini pour se référer à l'heure du dernier mirorring
              ` une fois fini plutôt qu'à son heure de début
				Fin de si 
				
				$hDelayUntil:=$hCurrentTime+$hDelayInterval
				Si ($hDelayUntil>?24:00:00?)
					$tDateTimeDelay:=GEN_tDateTimeStamp (Ajouter a date(Date du jour;0;0;1);$hCurrentTime+
                    $hDelayInterval-?24:00:00?)
				Sinon 
					$tDateTimeDelay:=GEN_tDateTimeStamp (Date du jour;$hDelayUntil)
				Fin de si 
				
				Repeter 
					$hDelayUntil:=Heure(Sous chaine($tDateTimeDelay;9;2)+":"
                     +Sous chaine($tDateTimeDelay;11;2)+":"+Sous chaine($tDateTimeDelay;13;2))
					
					Si (Num(Sous chaine($tDateTimeDelay;3;2))>(Jour de(Date du jour)))
               ` Prochaine planification après minuit
						$LDelayTicks:=($hDelayUntil+?24:00:00?)-$hCurrentTime*60
					Sinon 
						$LDelayTicks:=$hDelayUntil-$hCurrentTime*60
					Fin de si 
					ENDORMIR PROCESS(Numero du process courant;$LDelayTicks)
					  `TRACE
					  ` Il est possible qu'une machine Cliente puisse être en train de modifier l'intervalle de temps 
					  ` Si c'est vrai, l'heure doit être recalculée
					Au cas ou 
						: ($hDelayInterval=<>hMirror_TimeInterval)  ` Pas de changements nécessaires,
                       ` maintenir simplement le délai
							
						: ($hDelayInterval><>hMirror_TimeInterval)  ` l'intervalle du Mirroring est raccourci
							$hTimeChange:=($hDelayInterval-<>hMirror_TimeInterval)
							$hDelayUntil:=Heure(Sous chaine($tDateTimeDelay;9;2)+":"
                            +Sous chaine($tDateTimeDelay;11;2)+":"+Sous chaine($tDateTimeDelay;13;2))
							Si (Num(Sous chaine($tDateTimeDelay;3;2))>(Jour de(Date du jour))) 
                  ` L'heure prévue est pour demain
								$hDelayUntil:=$hDelayUntil+?24:00:00?
							Fin de si 
							
							Au cas ou 
								: (($hCurrentTime+$hTimeChange)<$hDelayUntil)  ` Le nouvel horaire est avancé
                              `par rapport à l'horaire planifié, simplement faire un reset sur le temps
									$hDelayUntil:=$hDelayUntil-$hTimeChange
									Si ($hDelayUntil>?24:00:00?)
										$tDateTimeDelay:=GEN_tDateTimeStamp (Ajouter a date(Date du jour;0;0;1);
                                   $hDelayUntil-?24:00:00?)
									Sinon 
										$tDateTimeDelay:=GEN_tDateTimeStamp (Date du jour;$hDelayUntil)
									Fin de si 
								: (($hCurrentTime+$hTimeChange)>$hDelayUntil)
									  ` L'ancien horaire précède le nouveau. Planifie avec l'ancien.
							Fin de cas 
							$hDelayInterval:=<>hMirror_TimeInterval  ` Reset pour la valeur courante
							
						Sinon   ` L'intervalle de Mirroring interval a été augmenté
							$hDelayUntil:=Heure(Sous chaine($tDateTimeDelay;9;2)+":"
                              +Sous chaine($tDateTimeDelay;11;2)+":"+Sous chaine($tDateTimeDelay;13;2))
							Si (Num(Sous chaine($tDateTimeDelay;3;2))>(Jour de(Date du jour)))
                              ` L'heure prévue est pour demain
								$hDelayUntil:=$hDelayUntil+?24:00:00?
							Fin de si 
							$hDelayUntil:=$hDelayUntil+(<>hMirror_TimeInterval-$hDelayInterval)
							Si ($hDelayUntil>?24:00:00?)
								$tDateTimeDelay:=GEN_tDateTimeStamp (Ajouter a date(Date du jour;0;0;1);
                                    $hDelayUntil-?24:00:00?)
							Sinon 
								$tDateTimeDelay:=GEN_tDateTimeStamp (Date du jour;$hDelayUntil)
							Fin de si 
							
							$hDelayInterval:=<>hMirror_TimeInterval  ` Reset pour la valeur courante
					Fin de cas 
					
				Jusque ((GEN_tDateTimeStamp (Date du jour;Heure courante)>=$tDateTimeDelay) |
                           (<>hMirror_TimeInterval=?00:00:00?))
				
				Si (<>hMirror_TimeInterval#?00:00:00?)  ` Nous n'arrêtons pas le mirroring
					$hCurrentTime:=Heure courante  ` Reset pour le prochain interval de temps
					$LErrorCode:=Miroir_EnvFichierHist 
					Au cas ou 
						: ($LErrorCode=1)  ` Mirroring réussi !
						Sinon 
							  ` Il est possible que vous souhaitiez figer le mirroring si une erreur 1403, 1412 ou 1410 survient
							  ` Une erreur 1409 survient quand des transactions empêchent la création d'un nouveau fichier                         `d'historique
							  ` Une erreur 1411 survient quand une opération critique empêche la création d'un nouveau
                       `fichier d'historique
							  ` Mais je vous laisse décider vous-mêmes
							  ` Si vous avez l'intention de stopper le mirroring, vous aurez besoin de modifier la
                       `ligne <>fQuitter pour arrêter la boucle
					Fin de cas 
				Fin de si 
				
			Jusque ((<>fQuitter) | (<>hMirror_TimeInterval=?00:00:00?))
		Fin de si 
		
Fin de cas 
  `Fin de méthode

Notez bien qu'il est possible que des erreurs fatales surviennent, empêchant les processus de mirroring suivants. Dans ce cas, je stoppe le processus de mirroring pour ne pas causer plus de dommages.

La méthode Miroir_EnvFichierHist fait le plus gros du travail. Premièrement, elle vérifie que le miroir est présent. Si le miroir n'est pas disponible, un nouveau fichier d'historique ne doit pas être créé.
code 4D

Si (Faux)
	  ` Methode: Miroir_EnvFichierHist
	  ` Note technique : mirroring avec 4D 2004
	  ` Créée par: Kent Wilbur
	  ` but: 
	
	<>f_Version2004x2:=Vrai
	<>fK_Wilbur:=Vrai
	
Fin de si 

  ` Declarer les parametres
C_ENTIER LONG($0)
C_BOOLEEN($1)

  ` Declare les variables locales
C_ENTIER LONG($LAbortCounter)
C_ENTIER LONG($LError)
C_ENTIER LONG($LLastSublogNumber)
C_ENTIER LONG($LPosition)
C_ENTIER LONG($LSMTPid)
C_TEXTE($tLastLogFile)
C_TEXTE($tLogFilePath)
C_TEXTE($tIntegrateType)

Mirror_LError:=0
$LError:=0
$LAbortCounter:=0

Si (Non(<>fQuitter))
	Au cas ou 
		: (proxy_SOAP_GererMiroir (<>tMirror_DatabaseName;"VerifyPresent";
                        <>tMirror_ServerIPAddress)#1)  ` la base de données n'est pas disponible
			$LError:=-17050
			SOAP_tErrorMessage:="La base miroir n'est pas disponible. Le Mirroring de "
             +Chaine(Heure courante;h mn )+" du "+Chaine(Date du jour;Format court )+" n'a pas eu lieu."
			
		Sinon 
			APPELER SUR ERREUR("ERROR_HandleMirrorError")
			$tLastLogFile:=Nouveau fichier historique 
              ` Retourne le chemin complet du fichier d'historique qui vient d'être fermé
			APPELER SUR ERREUR("")
	Fin de cas

Les erreurs sont capturées dans la méthode ERREUR_GestErreurMiroir qui assigne simplement une variable d'erreur (Error) à la variable Mirror_LError pour la gestion et la compréhension.
code 4D

Au cas ou 
		: (Mirror_LError=1409) | (Mirror_LError=1411)  ` Une transaction ou une operation critique est en cours
			$LAbortCounter:=$LAbortCounter+1
			Si ($LAbortCounter>10)
				$LError:=Mirror_LError
				SOAP_tErrorMessage:="Une transaction ou une operation critique bloque le mirroring.
                 Code d'erreur : "+Chaine(Mirror_LError)
			Fin de si 

Si la vérification de l'existence (VerifyPresence) du miroir passe sans problème, alors un nouveau fichier d'historique est créé. Si la création du nouveau fichier d'historique réussit, le fichier d'historique qui vient juste d'être fermé est stocké dans un BLOB et envoyé via SOAP au serveur miroir.

idea Note :
Comme je l'ai mentionné précédemment, j'utilise SOAP, mais d'autres mécanismes peuvent être développés.

N'hésitez pas à étudier le code de la méthode proxy_SOAP_GererMiroir, bien qu'elle ait été générée automatiquement par l'assistant Web Services et qu'elle n'ait pas été modifiée de manière significative, sauf pour utiliser les paramétrages des préférences pour la localisation du serveur miroir.
code 4D

		: (Longueur($tLastLogFile)>0)
			$tIntegrateType:="IntegrateLog"
			$LAbortCounter:=0
			
			DOCUMENT VERS BLOB($tLastLogFile;Mirror_oLogFile)
			Si (Taille BLOB(Mirror_oLogFile)>10000)  ` Si > sur 10 000 Ko, compresser le
               `blob pour réduire l'utilisation de la bande passante
				COMPRESSER BLOB(Mirror_oLogFile)
			Fin de si 
			
			$tLogFilePath:=GEN_tCheminDossier ($tLastLogFile)
			Si ($tLogFilePath#$tLastLogFile)  `extraire le chemin complet
				$tLastLogFile:=(Sous chaine($tLastLogFile;Longueur($tLogFilePath)+1))
			Fin de si 
			$LError:=proxy_SOAP_GererMiroir (<>tMirror_DatabaseName;$tIntegrateType;
                    <>tMirror_ServerIPAddress;->Mirror_oLogFile;$tLastLogFile) 
           ` Envoyer le fichier d'historique au serveur
			Si ($LError=1)
				<>tMirror_LastLogNumber:=$tLastLogFile
				Miroir_GestPrefsMiroir ("Save")  `sauvegarder
			Fin de si 
			FIXER TAILLE BLOB(Mirror_oLogFile;0)  ` libérer la mémoire
	Fin de cas 
	
Fin de si 

$0:=$LError

Pour finir, s'il y a des erreurs, des messages d'alertes seront envoyés par courrier électronique à l'adresse renseignée.
code 4D

Au cas ou 
	: ($LError=1)  ` Mirroring OK, rien de plus à faire
	: ($LError=0)  ` Mirroring ne s'est pas déclenché, mais il n'y a rien à faire
	: (Longueur(<>tMirror_SMTPServer)=0) & (<>tMirror_SMTPServer#"Aucun") 
            ` Rien à faire, pas d'erreur à envoyer
	: (Position(".";<>tMirror_SMTPServer)<1) | 
               ((Position(".";<>tMirror_SMTPServer))=(Longueur(<>tMirror_SMTPServer)))
		  ` format invalide pour le serveur de mail (il faut un point pour être valide et pas un point à la fin)
	Sinon 
		  ` Message d'erreur pour l'email
		  ` Note : ceci peut être ajouté à un système de messagerie existant dans une base de données
		  ` Si un tel système implique la sauvegarde d'enregistrements
		  ` Assurez-vous que ceci ne s'effectue PAS sur le serveur miroir, seulement sur le serveur principal
		  ` le problème avec cette solution est que si le serveur SMTP est HS, le message ne sera pas envoyé
		  ` donc avoir un système de messagerie déjà présent dans la base peut-être une meilleure solution
		$LError:=SMTP_New ($LSMTPid)
		$LError:=SMTP_Host ($LSMTPid;<>tMirror_SMTPServer)
		$LError:=SMTP_From ($LSMTPid;<>tMirror_ErrorEMailAccount)
		$LError:=SMTP_Subject ($LSMTPid;"Error with Mirroring for "+<>tMirror_DatabaseName)
		$LError:=SMTP_To ($LSMTPid;<>tMirror_ErrorEMailAccount)
		$LError:=SMTP_Body ($LSMTPid;SOAP_tErrorMessage)
		Si (<>tMirror_AuthenticationRequired="Yes")
			$LError:=SMTP_Auth ($LSMTPid;<>tMirror_AuthenticationUserName;
             <>tMirror_AuthenticationPassword)
		Fin de si 
		$LError:=SMTP_Send ($LSMTPid)
		$LError:=SMTP_Clear ($LSMTPid)
		
Fin de cas 
SOAP_tErrorMessage:=""
  `Fin de méthode

Côté serveur miroir


Le serveur miroir ne fait basiquement rien, si ce n'est "s'asseoir et attendre". Il ne fait même tourner aucun process. Si votre base de données utilise des procédures stockées qui tournent sur le serveur, il est préférable que vous les désactiviez et vérifiez que le serveur est un serveur miroir avant de lancer ces procédures stockées.

Quand un appel SOAP du serveur principal atteint la méthode d'entrée SOAP_GererEventsMiroir, le serveur miroir se met en marche. Il retourne 1 si l'action a réussi ou un code d'erreur si l'action a échoué.

Il possède deux actions. La première, vérifier que la base de données miroir existe avec le bon nom. La seconde, intégrer le fichier d'historique.
code 4D

Si (Faux)
	  ` Methode: SOAP_GererEventsMiroir
	  ` Note technique : mirroring avec 4D 2004
	  ` Créée par: Kent Wilbur
	
	  ` But: Gérer les requêtes SOAP pour le process du mirroring
	
	<>f_Version2004x2:=Vrai
	<>fK_Wilbur:=Vrai
	
Fin de si 

  ` Declarer les variables pour les types SOAP
C_BLOB(SOAP_oMirrorBLOB)
C_ENTIER LONG(SOAP_LMirrorResult)
C_TEXTE(SOAP_tMirrorAction)
C_TEXTE(SOAP_tMirrorDatabaseName)
C_TEXTE(SOAP_tMirrorLogFile)

  ` Declarer les variables locales
C_ENTIER LONG($LCompressed)
C_ENTIER LONG($LErrorCode)
C_TEXTE($tDatabasePath)
C_TEXTE($tDatabaseName)

DECLARATION SOAP(SOAP_tMirrorDatabaseName;Est un texte ;SOAP entrée ;
            "SOAP_tMirrorDatabaseName")
DECLARATION SOAP(SOAP_tMirrorAction;Est un texte ;SOAP entrée ;"SOAP_tMirrorAction")
DECLARATION SOAP(SOAP_oMirrorBLOB;Est un BLOB ;SOAP entrée ;"SOAP_oMirrorBLOB")
DECLARATION SOAP(SOAP_tMirrorLogFile;Est un texte ;SOAP entrée ;"SOAP_tMirrorLogFile")
DECLARATION SOAP(SOAP_LMirrorResult;Est un entier long ;SOAP sortie ;"SOAP_LMirrorResult")

LECTURE SEULEMENT(*)  ` définir les tables en lecture seules

$LErrorCode:=0
Mirror_LError:=0

$tDatabaseName:=Fichier structure
$tDatabasePath:=GEN_tCheminDossier ($tDatabaseName)
$tDatabaseName:=(Sous chaine($tDatabaseName;Longueur($tDatabasePath)+1))
Si (SOAP_tMirrorDatabaseName=$tDatabaseName)
	Au cas ou 
		: (SOAP_tMirrorAction="VerifyPresent")  `vérifier la présence de la base
			SOAP_LMirrorResult:=1  ` la base de données est ici
			
		: (SOAP_tMirrorAction="IntegrateLog@")  `intégrer le log
			LECTURE ECRITURE(*)  ` définir les tables en lecture écriture pour l'intégration du miroir
			LIRE PROPRIETES BLOB(SOAP_oMirrorBLOB;$LCompressed)
			Si ($LCompressed#Non compressé )
				DECOMPRESSER BLOB(SOAP_oMirrorBLOB)
			Fin de si 
			APPELER SUR ERREUR("ERREUR_GestErreurMiroir")
			BLOB VERS DOCUMENT($tDatabasePath+SOAP_tMirrorLogFile;SOAP_oMirrorBLOB)
			INTEGRER FICHIER HISTORIQUE($tDatabasePath+SOAP_tMirrorLogFile)
			APPELER SUR ERREUR("")
			Si (OK=1)
				SOAP_LMirrorResult:=OK
			Sinon 
				$LErrorCode:=Mirror_LError
			Fin de si 
			
			Si (SOAP_tMirrorAction="IntegrateLog&Backup")  `intégrer le log + backup
				SAUVEGARDER
			Fin de si 
			
	Fin de cas 
	
Sinon 
	$LErrorCode:=-17051
Fin de si 

Si ($LErrorCode#0)
	SOAP_LMirrorResult:=$LErrorCode
	SOAP_GererErreur ($LErrorCode)
Fin de si 
  `Fin de méthode

Si une erreur survient pendant l'intégration ou autre, l'erreur est traduite en numéro et message d'erreur, et une erreur SOAP est retournée à la base de données principale.
code 4D

Si (Faux)
	  ` Method: SOAP_GererErreur
	  ` Note technique : mirroring avec 4D 2004
	  ` Créée par: Kent Wilbur
	  ` but: contient les descriptions des erreurs 
	
	<>f_Version2004x2:=Vrai
	<>fK_Wilbur:=Vrai
	
Fin de si 

  `Declarer les parametres
C_ENTIER LONG($1;$LErrorCode)

  ` Reassigner pour la lisibilité
$LErrorCode:=$1

Au cas ou 
	: ($LErrorCode=-1403)
		SOAP_tErrorMessage:="Pas de fichier d'historique. La base miroir n'est pas configurée pour
                       avoir un fichier d'historique. "+"L'integration ne peut pas se faire."
	: ($LErrorCode=-1410)
		SOAP_tErrorMessage:="Les fichiers d'historique sont non synchronisés. L'intégration ne
                       peut pas se fai"+"re."+" Vous devez reconstruire le serveur miroir de zéro."
	: ($LErrorCode=-1412)
		SOAP_tErrorMessage:="La base miroir n'est pas lancée sous 4D Server.
                       L'intégration ne peut se faire qu'avec 4D Serveur."
	: ($LErrorCode=-17051)
		SOAP_tErrorMessage:="Nom de base de données invalide. Impossible de fusionner les
                       données dans la base avec ce nom. "+"Vérifiez les préférences du miroir."
Fin de cas 

ENVOYER ERREUR SOAP(SOAP erreur client ;Chaine($LErrorCode)+" - "+SOAP_tErrorMessage)
  `Fin de méthode

Maintenir les utilisateurs hors de la base miroir


Le serveur principal et le serveur miroir sont tous les deux sur le réseau. Il est donc probable qu'un utilisateur se connecte accidentellement au serveur miroir. Voici quelques petits choses que vous pouvez faire pour éviter que cela arrive.

D'abord, au moins, renommez le nom de publication sur le réseau de votre base de données miroir. Faites-le dans les préférences de la base, dans le panneau Client/Serveur.


Si la base de données est nommée différemment, il y a peu de chance qu'un utilisateur s'y connecte accidentellement.

Une solution plus sécurisante encore est de changer le numéro de port de publication pour le 4D Client. Ainsi l'application 4D Client normal ne peut pas accidentellement se connecter à la mauvaise base de données.

idea Note : n'oubliez pas de restaurer le numéro de port si vous avez besoin d'installer le miroir comme base principale.

Restauration d'urgence


Catastrophe mineure


Le système de mirroring est prévu pour restaurer rapidement une base de données suite à des catastrophes mineures. S'il y a beaucoup de petites catastrophes, j'appelle cela une catastrophe d'ordre majeur. Par petite catastrophe, je veux dire que la base de données sur le serveur principal est inopérante. Toutes les données sont perdues. La restauration est possible mais prendra des heures pour récupérer les données des sauvegardes.

Si vous avez accès au disque dur du serveur principal pour retrouver le dernier fichier d'historique ouvert qui n'a pas encore été intégré à la base, la restauration est facile. Le dernier fichier d'historique a besoin d'être intégré dans la base miroir. Ci-dessous vous trouverez les démarches nécessaires pour la base exemple. Pour vos propres bases, vous devrez utiliser au moins quelques-uns de ces points :

1 - Déplacer simplement le fichier d'historique sur un 4D Client, dans un dossier spécifique. C'est nécessaire car le dernier fichier d'historique aura besoin d'être fusionné avec la machine miroir avant qu'il puisse être installé sur le serveur principal. La commande INTEGRER FICHIER HISTORIQUE ne peut être appliquée que sur le serveur. C'est pourquoi la machine du 4D Client va temporairement prendre la place du serveur principal crashé et envoyer le dernier fichier au serveur miroir pour l'intégrer.

2 - Lancer le 4D Client et se connecter à la base miroir. Selon les mesures de sécurité choisies plus haut, il est possible qu'il soit nécessaire de changer le numéro de port soit du 4D Client soit du 4D Server.

3 - Aller en mode utilisation et exécuter la méthode E_RestDataLogsMiroir. Nous étudierons ce code dans le prochain chapitre.

4 - Sélectionner le fichier d'historique à fusionner.

5 - Aller sur le serveur et modifier le numéro de port si besoin.

6 - Quitter le serveur miroir.

7 - Supprimer les préférences du miroir.

8 - Lancer le serveur et sélectionner le serveur qui sera le serveur principal. Vous voilà à nouveau opérationnel.

Si vous ne pouvez pas récupérer le dernier fichier d'historique ouvert vous devrez le faire sans ces données. Dans ce cas, passez les points 1 à 4 ci-dessus et allez directement au point 5.


Catastrophe majeure


Le pire scénario possible est que les données du serveur principal et du serveur miroir soient endommagées. Dans ce cas, vous devez reprendre une sauvegarde et repartir de là. Cependant, la sauvegarde originale ne contient aucun des segments du fichier d'historique. Il n'est pas important de savoir quel base de données est utilisée. Suivez cette procédure ci-dessous pour récupérer une base suite à une catastrophe majeure.

1 - Restaurer la base de données à partir de la dernière sauvegarde

2 - Déplacer tous les fichiers d'historiques sur le 4D Client dans un dossier à part

3 - Lancer le 4D Client and connectez-vous au serveur

4 - Aller en mode Utilisation et exécuter la méthode E_RestDataLogsMiroir

5 - Sélectionnez un des fichiers d'historiques à être fusionné

6 - Après l'avoir intégré, faites une sauvegarde et lancez le tout à nouveau en installant le miroir comme base principale. Vous êtes à nouveau opéationnel.

idea Note : il est possible qu'il soit nécessaire de fusionner séparément le fichier d'historique final comme vous l'avez fait dans les points plus haut lors de la restauration après une catastrophe mineure : le code ne distingue pas les segments de log qui sont actifs ou fermés.
code 4D

Si (Faux)
	  ` Method: E_RestDataLogsMiroir
	  ` Note technique : mirroring avec 4D 2004
	  ` Créée par: Kent Wilbur
	
	  ` But:  Intègre les fichiers d'historique dans la base de données restaurées depuis une sauvegarde
	  ` pas le miroir
	
	<>f_Version2004x2:=Vrai
	<>fK_Wilbur:=Vrai
	
Fin de si 

  ` Declarer les variables locales
TABLEAU TEXTE($atDocuments;0)
TABLEAU TEXTE($atLogFiles;0)
C_BLOB($oBlob)
C_ENTIER LONG($i)
C_ENTIER LONG($LApplicationType)
C_ENTIER LONG($LError)
C_ENTIER LONG($LPid)
C_ENTIER LONG($LPosition)
C_TEXTE($tFileName)
C_TEXTE($tFolderPath)
C_HEURE($hDocRef)

$LApplicationType:=Type application

Au cas ou 
	: ($LApplicationType=4D Client )
		ALERTE("Veuillez localiser le fichier d'historique à intégrer.")
		
		$hDocRef:=Ouvrir document("";"";Lire chemin accès )
                 ` montre tous les fichiers, mais si un historique n'est pas sélectionné, ça ne marchera pas
		
		Si (OK=1)
			FERMER DOCUMENT($hDocRef)
			$tFolderPath:=GEN_tCheminDossier (Document)
			$tFileName:=Sous chaine(Document;Longueur($tFolderPath)+1) 
                  ` retourne le nom du fichier d'historique sélectionné
			
			  ` retourne les infos nécessaires du serveur
			SOAP_tMirrorDatabaseName:=""
			tMirror_ThisServerIPAddress:=""

Bien que nous travaillons sur une machine 4D Client, il est plus facile d'intégrer le fichier d'historique en utilisant les mêmes méthodes SOAP utilisées par le serveur principal. Le code d'intégration (SOAP) a besoin du nom de la base et de l'adresse IP du serveur miroir. Ces données NE SONT PAS dans les préférences du miroir. Donc, nous allons utiliser une communication par interprocess entre le Client et le Serveur. Le code suivant lit les valeurs par la commande LIRE VARIABLE PROCESS.
code 4D

			$LPid:=Executer sur serveur("E_RestoreDataFromMirrorLogs";32000)
			Repeter 
				PROCESS_MonDelai (Numero du process courant;2)  ` attend les informations du serveur
				LIRE VARIABLE PROCESS($LPid;SOAP_tMirrorDatabaseName;SOAP_tMirrorDatabaseName)
				LIRE VARIABLE PROCESS($LPid;tMirror_ThisServerIPAddress;tMirror_ThisServerIPAddress)
			Jusque (Longueur(SOAP_tMirrorDatabaseName)>0)

Les segments du fichier d'historique ont un format spécifique [0000-0000]. Si nous fusionnons plusieurs segments nous chercherons ce format et nous fusionnerons tous les fichiers qui correspondent à cette séquence dans leur nom de fichier et qui ont le numéro principal de sauvegarde adéquat.
code 4D

			$LPosition:=Position("[";$tFileName)
			Si ($LPosition+10=Position("]";$tFileName))  ` s'assurer qu'on a bien les historiques
              ` du miroir à fusionner, et pas les historiques "normaux"
				  ` nous devons retrouver tous les fichiers d'historiques correspondants
				LISTE DES DOCUMENTS($tFolderPath;$atDocuments)
				
				Boucle ($i;1;Taille tableau($atDocuments))
					
					Au cas ou 
						: (Longueur($tFileName)#Longueur($atDocuments{$i})) 
                                ` pas la même longueur, pas un historique
						: (Sous chaine($tFileName;1;$LPosition+5)#Sous chaine($atDocuments{$i};1;$LPosition+5)) 
                                ` pas le même fichier de donnees ni numéro de sauvegarde
						: (Sous chaine($tFileName;$LPosition+10)#Sous chaine($atDocuments{$i};$LPosition+10)) 
                                ` pas un historique
						Sinon 
							AJOUTER A TABLEAU($atLogFiles;$atDocuments{$i})
					Fin de cas 
				Fin de boucle 
				
				Si (Taille tableau($atLogFiles)>0)  ` Intègre les fichiers d'historique
					TRIER TABLEAU($atLogFiles)
					Boucle ($i;1;Taille tableau($atLogFiles))
						
						DOCUMENT VERS BLOB($tFolderPath+$atLogFiles{$i};Mirror_oLogFile)
						Si (Taille BLOB(Mirror_oLogFile)<10000)  ` si plus grand que 10 000 octets,
                     `compresser le blob pour réduire l'utilisation de la bande passante
							COMPRESSER BLOB(Mirror_oLogFile)
						Fin de si 
						$LError:=proxy_SOAP_GererMiroir (SOAP_tMirrorDatabaseName;
                       "IntegrateLog";tMirror_ThisServerIPAddress;->Mirror_oLogFile;$atLogFiles{$i})  
                       ` envoie le fichier d'historique au serveur
						Si ($LError#1)
							ALERTE("Gros Problème!")
							$i:=Taille tableau($atLogFiles)
						Fin de si 
						FIXER TAILLE BLOB(Mirror_oLogFile;0)  ` libère la mémoire
						
					Fin de boucle 
				Fin de si 

Intégrer un seul fichier d'historique :
code 4D

			Sinon   ` Ajouter un fichier d'historique
				DOCUMENT VERS BLOB($tFolderPath+$tFileName;Mirror_oLogFile)
				Si (Taille BLOB(Mirror_oLogFile)<10000)  ` si plus grand que 10 000 octets, compresser le blob
              `pour réduire l'utilisation de la bande passante
					COMPRESSER BLOB(Mirror_oLogFile)
				Fin de si 
				$LError:=proxy_SOAP_GererMiroir(SOAP_tMirrorDatabaseName;"IntegrateLog";
                  tMirror_ThisServerIPAddress;->Mirror_oLogFile;$tFileName)
                 ` envoie le fichier d'historique au serveur
				
				Si ($LError#1)
					ALERTE("Le fichier d'historique a été fusionné !")
				Fin de si 
				FIXER TAILLE BLOB(Mirror_oLogFile;0)  ` libère la mémoire
				
			Fin de si 
		Fin de si 

C'est ici que le 4D Serveur cherche ses informations et les sauvegarde dans des variables process. Une fois sauvegardé, le process se met en attente quelques secondes et meurt. Pendant ces quelques secondes, le code donné plus haut lit le contenu des variables process.
code 4D

	: ($LApplicationType=4D Server )
		SOAP_tMirrorDatabaseName:=""
		$LError:=IT_MyTCPAddr (tMirror_ThisServerIPAddress;$tFileName)
		$tDatabaseName:=Fichier structure
		$tDatabasePath:=GEN_tCheminDossier ($tDatabaseName)
		SOAP_tMirrorDatabaseName:=(Sous chaine($tDatabaseName;Longueur($tDatabasePath)+1))
		PROCESS_MonDelai (Numero du process courant;300)  ` laisse le process tourner
           `assez longtemps pour récupérer la valeur de la variable
		
	Sinon 
		ALERTE("Les fichiers d'historique ne peuvent être intégrés que depuis une machine cliente"+"
             avec 4D Client.")
Fin de cas 
  `Fin de méthode

La fonction Nouveau fichier historique et opérations critiques


La fonction Nouveau fichier historique et quelques opérations critiques comme les transactions et l'indexation sont mutuellement exclusives. Par exemple, vous ne pouvez pas créer un nouveau fichier d'historique pendant que le 4D Client ou une procédure stockée est en pleine transaction. Et vous ne pouvez pas débuter une nouvelle transaction pendant que Nouveau fichier historique est en cours.

Si votre base de données utilise les transactions, vous devrez planifier votre procédure de mirroring pour la lancer quand il n'y a plus d'utilisateurs actifs sur la base de données. Si des transactions sont en cours pendant la fonction Nouveau fichier historique, il est possible que le serveur gèle pendant quelques minutes, attendant la fin des transactions. Vous pouvez diminuer l'attente en modifiant quelques paramétrages par défaut dans les préférences de sauvegarde de la base de données.

Dans les paramètres généraux, assurez-vous que le bouton radio "Annuler la sauvegarde après une attente de n minutes" est sélectionné. Modifiez aussi le temps par défaut de 3 à 1 minute.


Ne mettez pas 0 minute. L'effet sera que la sauvegarde attend la fin des transactions mais n'arrive jamais au timeout. Au besoin vous pouvez vérifier la bonne marche de la fonction Nouveau fichier historique en testant le code d'erreur éventuel. Si le code d'erreur est 1411, la fonction Nouveau fichier historique échoue à cause d'une opération critique. Habituellement parce qu'un transaction était en cours. Votre planification pourrait réessayer jusqu'à ce que la fonction réussisse, ou attendre le prochaine lancement de l'opération. Ceci n'a pas été programmé dans la base exemple.


Conclusion


Créer un système de mirroring n'est plus une tâche purement administrative. La coopération du développeur est requise pour son implémentation. Ce n'est cependant pas une tâche difficile à accomplir. Les administrateurs de base de données 4D avaient souvent des problèmes pour installer un miroir, le développeur était donc de toutes façons impliqué.

Les nouvelles commandes du mirroring rendent la chose plus flexible que dans les versions précédentes de 4D. Une interface conviviale peut être créée aisément pour administrer le mirroring.

Même si le mirroring était possible avec 4D 2004.2, je recommande d'utiliser au minimum 4D 2004.3 qui fixe un bug mineur (même si la base exemple ne l'aurait même pas rencontré).

La plupart des bases de données 4D n'ont pas besoin de base miroir. Mais pour celles dont c'est le cas, je suggère que vous vous penchiez sur ce qu'il est possible de faire avec ces deux nouvelles commandes.

Nouveau fichier historique

INTEGRER FICHIER HISTORIQUE


Télécharger la base exemple


Télécharger la base exemple.

__________________________________________________
Copyright © 1985-2009 4D SA - Tous droits réservés
Tous les efforts ont été faits pour que le contenu de cette note technique présente le maximum de fiabilité possible.
Néanmoins, les différents éléments composant cette note technique, et le cas échéant, le code, sont fournis sans garantie d'aucune sorte. L'auteur et 4D S.A. déclinent donc toute responsabilité quant à l'utilisation qui pourrait être faite de ces éléments, tant à l'égard de leurs utilisateurs que des tiers.
Les informations contenues dans ce document peuvent faire l'objet de modifications sans préavis et ne sauraient en aucune manière engager 4D SA. La fourniture du logiciel décrit dans ce document est régie par un octroi de licence dont les termes sont précisés par ailleurs dans la licence électronique figurant sur le support du Logiciel et de la Documentation afférente. Le logiciel et sa documentation ne peuvent être utilisés, copiés ou reproduits sur quelque support que ce soit et de quelque manière que ce soit, que conformément aux termes de cette licence.
Aucune partie de ce document ne peut être reproduite ou recopiée de quelque manière que ce soit, électronique ou mécanique, y compris par photocopie, enregistrement, archivage ou tout autre procédé de stockage, de traitement et de récupération d'informations, pour d'autres buts que l'usage personnel de l'acheteur, et ce exclusivement aux conditions contractuelles, sans la permission explicite de 4D SA.
4D, 4D Calc, 4D Draw, 4D Write, 4D Insider, 4ème Dimension ®, 4D Server, 4D Compiler ainsi que les logos 4e Dimension, sont des marques enregistrées de 4D SA.
Windows,Windows NT,Win 32s et Microsoft sont des marques enregistrées de Microsoft Corporation.
Apple, Macintosh, Power Macintosh, LaserWriter, ImageWriter, QuickTime sont des marques enregistrées ou des noms commerciaux de Apple Computer,Inc.
Mac2Win Software Copyright © 1990-2002 est un produit de Altura Software,Inc.
4D Write contient des éléments de "MacLink Plus file translation", un produit de DataViz, Inc,55 Corporate drive,Trumbull,CT,USA.
XTND Copyright 1992-2002 © 4D SA. Tous droits réservés.
XTND Technology Copyright 1989-2002 © Claris Corporation.. Tous droits réservés ACROBAT © Copyright 1987-2002, Secret Commercial Adobe Systems Inc.Tous droits réservés. ACROBAT est une marque enregistrée d'Adobe Systems Inc.
Tous les autres noms de produits ou appellations sont des marques déposées ou des noms commerciaux appartenant à leurs propriétaires respectifs.
__________________________________________________
 



Valid XHTML 1.1!Valid CSS!

Ce document est issu de http://www.developpez.com et reste la propriété exclusive de son auteur. La copie, modification et/ou distribution par quelque moyen que ce soit est soumise à l'obtention préalable de l'autorisation de l'auteur.
Contacter le responsable de la rubrique 4D