Große Tabellen

Es ist interessant zu sehen, wie große Tabellen sich in Echtzeit oder zumindest interaktiv ohne gefühlte Verzögerung handhaben lassen.

Vielleicht war es einmal praktisch, daß Telefonnummern oder Nummernschilder in vielen regionalen kleinen Tabellen strukturiert waren, die dann jeweils maximal wenige Millionen Einträge enthielten. Auch Bankkonten wurden an den einzelnen Standorten geführt und man mußte zum Abheben bei einer anderen Filiale derselben Bank warten, bis die zuständige Filiale kontaktiert worden war. Fahrkarten konnte man für inländische Zugverbindungen kaufen, aber für ausländische Verbindungen war ein Sonderschalter zuständig, und für Auslandsreservierungen mußte man zweimal vorbeikommen. Telefonbuchabfragen im Internet waren möglich, aber man mußte doch erst den Ort angeben und dann den Namen, selbst wenn es ein seltener Name war.

Heute sieht man, daß es kein Problem mehr ist, einen flachen Nummernraum für ein ganzes Land für Telefonnummern, Nummernschilder oder andere in ähnlicher Häufigkeit vorhandene Daten zu haben. Praktisch ist das zum Beispiel, weil man innerhalb von der Schweiz umziehen kann, ohne die Telefonnummer zu ändern, aber für die Mobiltelefone hat man ja schon von Anfang an auf regionalisierte Nummern verzichtet, früher weil es so wenige Mobiltelefone gab und heute, weil man mit 100 Millionen Mobiltelefonnummern in Echtzeit umgehen kann.

Share Button

Some thoughts about ssh

Deutsch

In the good old days, when the participants of the Internet still kind of knew each other, it was reasonable to trust each other, because the bad guys where not likely among the few and they did not have much to gain there from an ordinary user. So it was common to use telnet or rlogin or sethost to connect to other computers. Usually the password was transmitted unencrypted, which was actually quite irresponsible.

Today we have to use ssh instead and it does pretty much what telnet could do in the old days, but also quite a bit more, even much more than can be mentioned in these lines. It is not only important to transmit the password in an encrypted way, but also to ensure that the other side is really the desired node, not some man in the middle, trying to capture the password, which would leave us where we were with telnet.

For this purpose the .ssh-directory contains those certificates, which are files like id_rsa and id_rsa.pub. The id_rsa should be kept safe. They must not be given away, but they should also not be changed, which means that they should not be lost, because they are hard to reproduce, otherwise they would not be secret. The security of the whole protocol depends on this. With ssh-keygen it is possible to create such certificates, optionally in such a way that a password needs to be provided prior to using it. This password remains within the local computer. Certificates have fingerprints, that can be shown with ssh-keygen -l. Exactly this fingerprint will be shown when logging into a node from some other node for the first time and it needs to be confirmed. So it is important to make sure that the fingerprints have been transferred on a safe channel prior to this login, because otherwise we could possibly just confirm the fingerprint of the man in the middle. This is like with infectious diseases. It is necessary to work in a very hygienic way all the way, otherwise the security is at risk. A good way might be to start the first ssh-session to some node in a cabled network, where the cable and network topology is well known and trusted and simple enough to assume that the network traffic really goes to the desired host. Another way is to write down the fingerprint on paper or to print it or to use a USB stick to copy it to the host from which ssh is initiated. With this first login an entry to .ssh/known_hosts is created, which will be used subsequently. As long as .ssh/known_hosts contains no corrupted entries, it will be very hard for a man in the middle to do his evil job and the whole process provides a reasonable level of security.

Now the public key from id_rsa.pub of the own computer can be transferred to the remote computer and added to .ssh/authorized_keys on the remote hosts. This results in the possibility to log into that host without the need to enter a password, unless the local certificate needs a password, which it should in such a case. For convenience this password needs to be typed only once per session by calling ssh-add.

ssh is used even for other purposes, because it supports tunneling of other protocols like subversion or git.

Very beautiful is the possibility to use ssh in conjunction with X11 by calling

ssh -X user@host

This allows to start graphical applications on the remote computer and they are displayed on the local computer. The x11-windowing system is network enabled and uses the ssh tunnel.

Redirection of displays has been common practice in the Unix and Linux-world for more than 25 years, but with ssh it is much more secure than with the unencrypted protocols that ware used in the old days. Who of you still knows xhost +?

All of this is referring to ssh for Linux, but it should work exactly the same way on all kinds of recent Unix systems like Solaris or BSD variants. On MS-Windows-computers it is possible and useful to install putty. Many of the capabilities of ssh can be found in putty as well, just packaged and used in a different way. I actually prefer to use cygwin and its ssh implementation on MS-Windows, which is very similar to the Linux-ssh. It is even possible to build up an ssh-server with MS-Windows using cygwin, but this is not so easy.

Share Button

PDF mit Ruby erzeugen

Es gibt viele Libraries, die mit Ruby, Perl, Java oder was auch immer man so verwendet, PDF-Dateien erzeugen. Das Prinzip ist oft so, daß man eine Art Formular erstellt, in dem dann Platzhalter mit Daten aus dem Programm gefüllt werden. Im Prinzip sehr ähnlich wie das Generieren von HTML-Seiten in vielen Web-Applikationen.

Heute verwendet man für Webapplikationen mit Ruby on Rails HAML. Die älteren Rails-Entwickler erinnern sich aber noch teilweise daran, daß man früher einmal erb verwendet hat. Man hat also das HTML so hingeschrieben, wie es halt aussieht und die Platzhalter dann mit so etwas wie <%= some_ruby_code => ausgefüllt. Es war sogar möglich, Schleifen und Bedingte Codeteile zu haben, dafür hat man dann so etwas wie

<% number.times do |x| %>
...
<%= function(x) %>
...
<% end %>

geschrieben. In HAML ist das alles viel schöner, weil man eine Syntax hat, die den Ruby und den HTML-Code viel eleganter miteinander integriert. Aber HAML ist für HTML gemacht.

Um nun PDF-Dateien zu generieren, lohnt es sich, Text-Formate anzusehen, die zu PDF konvertiert werden können. Möglich wäre zum Beispiel PostScript, aber auch die Formate heutiger Office-Systeme wie MS-Office und LibreOffice und OpenOffice sind grundsätzlich dokumentiertes XML, also durchaus zugänglich, wenn man viel Zeit hat. Ob nun XML wirklich als Textformat zählt oder doch eher als Binärformat mit einzelnen Merkmalen eines Textformats, muß die Praxis zeigen. Viele XML-Formate sind fast so unzugänglich wie Binärdateien. Wer sich mit diesen Office-Systemen auskennt, kann auch Libraries verwenden, die diese direkt generieren oder die die APIs der entsprechenden Software ansprechen, wenn man eine entsprechende Installation erreichen kann. Auf typischen Serversystemen ist das schon eine gewisse Hürde.

Ein schönes Textformat ist LaTeX oder TeX. Das sind Satzsysteme, die das Layout in einer textbasierten Sprache, man kann sagen einer Programmiersprache, beschreiben. Text wird einfach so geschrieben, für mathematische und chemische Formeln gibt es sehr leistungsfähige Funktionen, die ich hier in diesem Blog auch regelmäßig für Formeln verwende, wenn es nötig ist. Und ansonsten gibt es Macros, die mit „\“ anfangen. Diese Macros machen TeX zu einer vollwertigen, aber nicht sehr zugänglichen Programmiersprache, aber für einfache Layouts kann man sich Muster im Internet oder von Kollegen oder aus Büchern holen und anpassen und das Lernen der Macrosprache weitgehend der Zukunft oder anderen überlassen. Weil das nun wirklich „plain“-Text ist, läßt sich sehr gut mit erb arbeiten und ein LaTeX-Template erstellen, in dem dann die Daten aus der Software eingefüllt werden, einschließlich Dingen wie Tabellen, bei denen z.B. die Anzahl der Zeilen dynamisch ist.

Mit diesem Ansatz generiere ich seit dem Bestehen der Firma IT Sky Consulting GmbH alle Rechnungen, die an Kunden verschickt werden. Es muß wohl funktioniert haben, denn ohne lesbare Rechnungen kann kaum eine Firma mehrere Jahre überleben. 😉

Share Button

Zeichenketten in Java, Ruby und Perl

Eigentlich sind die Zeichenketten in allen Programmiersprachen das gleiche, man kann sie als Literale angeben, irgend woher lesen oder zusammensetzen und dann vergleichen und ausgeben.

Aber es gibt einen großen Unterschied. In Java und in den JVM-Sprachen Scala und Clojure, die sich nicht speziell dagegen gewehrt haben, sind die normalen Zeichenketten unveränderlich. Das bedeutet, dass bei jeder Operation, die eine Zeichenkette zu verändern scheint, in Wirklichkeit jeweils eine neue Zeichenkette generiert wird. Das erschwert die Handhabung der Zeichenketten etwas, hat aber den Vorteil, dass man nicht durch Manipulationen an einer Zeichenkette anderen Programmteilen den Teppich wegziehen kann. Bei Multi-Thread-Programmen ist das besonders gefährlich, aber auch ohne mehrere Threads zu verwenden könnte das zu unerwarteten Fehlern führen, aber für Manipulationen kann es etwas unpraktischer sein, weil jedes Mal eine neue Zeichenkette generiert werden muss. Für diese Zwecke gibt es aber StringBuilder und StringBuffer, die explizit veränderliche Zeichenketten darstellen und für längere Manipulationen als Zwischenergebnis gut geeignet sind, aber man sollte diese am Schluss mit toString() in eine normale Zeichenkette umwandeln, die nicht mehr veränderlich ist. Da Scala und Clojure das Lied der unveränderlichen Objekte singen und als funktionale Sprachen oder teilweise funktionale Sprachen solche unveränderlichen Objekte der Normalfall sind, passt dieses Konzept dort sehr gut hinein.

In Perl und Ruby kann man sehr viele Manipulationen mit Zeichenketten machen, man könnte sogar fast sagen, dass diese Manipulationen von Zeichenketten mit regulären Ausdrücken die Stärke von Perl sind und deshalb auch sehr häufig vorkommen. Aber auch Perl und Ruby haben sich davor geschützt, dass man den Schlüssel (engl. key) einer Map verändert:

Beispiel in Ruby:

$ irb
irb(main):001:0> x="abc"
=> "abc"
irb(main):002:0> y="def"
=> "def"
irb(main):003:0> m={x=>3, y=>4}
=> {"abc"=>3, "def"=>4}
irb(main):004:0> x += "x"
=> "abcx"
irb(main):005:0> x
=> "abcx"
irb(main):006:0> m
=> {"abc"=>3, "def"=>4}
irb(main):007:0> y.gsub!(/d/, "x")
=> "xef"
irb(main):008:0> m
=> {"abc"=>3, "def"=>4}
irb(main):009:0>

Man sieht also, dass auch hier sichergestellt wird, dass das Verändern der Zeichenkette nicht die Schlüssel der Map verändert.

In Perl verhält es sich ähnlich:

$ perl
$x = "abc";
$y = "def";
%m = ($x, 3, $y, 4);
$x =~ s/a/A/;
print "x=$x y=$y\n";
print "m{x}=", $m{$x}, " m{'abc'}=", $m{'abc'}, " m(y)=", $m{$y},"\n";

Ctrl-D

x=Abc y=def
m{x}= m{'abc'}=3 m{y}=4

Die Zeichenketten werden beim Anlegen der Map %m kopiert und deshalb passiert nichts, wenn man nachträglich noch $x und $y ändert. Bei Ruby ist das entsprechend.

Man kann dies aber austricksen, zum Beispiel in Ruby:

$ irb
irb(main):001:0> class X
irb(main):002:1> attr_accessor :x
irb(main):003:1> def initialize(x)
irb(main):004:2> @x = x
irb(main):005:2> end
irb(main):006:1> end
=> nil
irb(main):007:0> x = X.new("abc")
=> #
irb(main):008:0> y = X.new("def")
=> #
irb(main):009:0> m={x=>3, y=>4}
=> {#=>3, #=>4}
irb(main):010:0> m
=> {#=>3, #=>4}
irb(main):011:0> x.x="abcd"
=> "abcd"
irb(main):012:0> x
=> #
irb(main):013:0> m
=> {#=>3, #=>4}
irb(main):014:0> y.x.gsub!(/d/, "D")
=> "Def"
irb(main):015:0> y
=> #
irb(main):016:0> m
=> {#=>3, #=>4}

Das lässt sich entsprechend in Perl und Java auch tun, führt eher zu überraschenden als erwünschten Ergebnissen und ist nicht zu empfehlen. In Ruby kann man die Schlüssel einer Map mit freeze() schützen:

irb(main):017:0> x.freeze
=> #
irb(main):018:0> x.x="u"
RuntimeError: can't modify frozen object
from (irb):18
from /usr/local/bin/irb:12:in `

'

Das ist ein recht eleganter Mechanismus, weil man ein Objekt mit einigen komplexeren Schritten initialisieren kann und dann durch freeze() schützen kann. Aber Vorsicht, es ist kein deepfreeze(), dies muss man explizit sicherstellen:

irb(main):019:0> x.x.gsub!(/a/, "u")
=> "ubcd"
irb(main):020:0> x
=> #
irb(main):021:0> x.x.freeze
=> "ubcd"
irb(main):022:0> x.x.gsub!(/a/, "u")
RuntimeError: can't modify frozen string
from (irb):22:in `gsub!'
from (irb):22
from /usr/local/bin/irb:12:in `
'

Eine interessante Frage ist oft, ob zwei Zeichenketten mit demselben Inhalt in Wirklichkeit dieselbe Zeichenkette sind oder ob es identische Kopien sind. Normalerweise ist das ja egal, aber es spielt eine Rolle bei Vergleichen. Diese sind billiger, wenn man sofort erkennt, ob es dasselbe Objekt ist und nicht erst zeichenweise vergleichen muss. Wenn große Datenmengen verarbeitet werden, ist es aber auch manchmal wegen des Speicherverbrauchs relevant.

Man kann in allen drei Sprachen beide Fälle haben. Mit zwei Variablen dieselbe Zeichenkette zu referenzieren ist in Java und Ruby einfach.

x = "abc";
y = x;

(in Ruby darf man die „;“ weglassen.)
In Perl sind die Variablen nicht Referenzen, sondern es werden wirklich Werte kopiert. Man muß dazu also explizit Referenzen verwenden:

$ perl
$x="abc";
$u=\$x;
$v=\$y;
print "x=$x u=$u v=$v\n";
$$u =~ s/a/A/;
print "x=$x u=$u v=$v\n";
print '$$u=', $$u, ' $$v=', $$v, ' $x=', $x,"\n";
Ctrl-D

x=abc u=SCALAR(0x8069820) v=SCALAR(0x80698ac)
x=Abc u=SCALAR(0x8069820) v=SCALAR(0x80698ac)
$$u=Abc $$v= $x=Abc

Umgekehrt kann man aber auch echte Kopien erzwingen, wenn man das will:
In Java geht das so:

String x = "abc";
String y = new String(x);

Oder in Ruby:

x = "abc"
y = String.new(x)

und in Perl ist es trivial:

$x = "abc";
$y = $x;

reicht schon aus.

Nun gewinnt man beim Vergleichen und beim Speicherverbrauch schon etwas, wenn man möglichst oft bei Vergleichen, die am Ende „true“ ergeben, schon an der Objektidentität und nicht erst am Vergleich aller Zeichen die Gleichheit erkennt. Aber wenn bei der Mehrheit der Vergleiche zwar die Länge gleich ist, aber die Zeichen sich irgendwo weit hinten unterscheiden, arbeitet das Programm vielleicht immer noch zu viel für diese Vergleiche. Wenn man also große Datenmengen verarbeiten will oder einfach nur meint, dass der Vergleich über die Objektidentität „richtiger“ ist, lässt sich das in Java und Ruby recht gut erzwingen.

In Java etwa mit

import java.util.IdentityHashMap;

public class MyMap extends IdentityHashMap {
public V put(String key, V value) {
assert key != null;
String uniqueKey = key.intern();
return super.put(uniqueKey, value);
}

public V get(Object key) {
if (key instanceof String) {
String str = (String) key;
return super.get(str.intern());
} else {
return null;
}
}
//..

public static void main(String args[]) {
MyMap map = new MyMap();
System.out.println(map.put("abc", "uvw"));
System.out.println(map.put(new String("abc"), "def"));
System.out.println(map.get("abc"));
System.out.println(map.get(new String("abc")));
}
}

ergibt die Ausgabe:

null
uvw
def
def

und verwendet intern nur die billigen Vergleiche mit == statt mit .equals(..).

In Ruby verwendet man dafür einfach „Symbole“ statt Zeichenketten, etwa

m = { :a => 3, :b => 4, :c => 5 }

Vorsicht ist aber geboten, sobald man Frameworks benutzt, die serialisieren, um Daten zu persistieren oder über das Netz zu schieben. Beim Deserialisieren geht diese Identität der Zeichenketten leider ganz schnell verloren, vor allem, wenn man „über das Netz“ vergleicht, was ja vorkommen kann.

Nun sei noch ein Grund erwähnt, warum man Java-Zeichenketten überhaupt mit so etwas wie y=new String(x) kopiert, wo sie doch unveränderbar (immutable) sind. Hier sollte man eine Optimierung in der Implementierung von String kennen. Wenn man substring() aufruft, wird ein neues String-Objekt für die Unterzeichenkette angelegt, dieses referenziert aber die Zeichensequenz der ursprünglichen Zeichenkette, nur mit anderen Anfangs- und Endzeigern. Dadurch wird in der Regel Speicher gespart und auch der Aufwand für das Allozieren von neuem Speicher vermieden. Wenn man nun aber von einer sehr langen, kurzlebigen Zeichenkette mit substring() eine sehr kurze, aber langlebige Zeichenkette extrahiert, verhindert man damit, dass der Speicher der eigentlichen Zeichensequenz der langen Zeichenkette freigegeben wird. So raffiniert und richtig es also in den allermeisten Fällen ist, die Optimierung der Library zu nutzen und zu schreiben

String y = x.substring(r, s);

so sollte man doch beachten, dass es in seltenen Fällen richtig und sogar wichtig ist, stattdessen

String y = new String(x.substring(r, s));

zu schreiben. Im Zweifelsfalls sollte man aber immer bei der ersten Schreibweise bleiben. Programme, die wegen ein paar Zeichenketten Memoryprobleme bekommen, die sich nicht durch Erhöhen der Speicherparameter leicht lösen lassen, sind zum Glück sehr selten.

Interessant ist sicher noch die Frage, in welcher Codierung die Zeichenketten gespeichert werden und wie man sie bei Ein- und Ausgabe richtig konvertiert. Das ist aber sicher genug Stoff für einen eigenen Artikel. Hier sei nur soviel gesagt: Java speichert die Zeichenketten mit utf-16, braucht also zwei Byte pro Zeichen, auch bei europäischen Sprachen.

Share Button

Jolla will noch dieses Jahr Mobiltelefone mit SailfishOS bringen

Share Button

Ein paar Gedanken zu ssh

English

Früher, als man noch jedem im Internet und sogar im Intranet vertraute, hat man sich ja einfach mit telnet in andere Rechner eingeloggt. Oder mit rlogin, damit die Umlaute auch funktioniert haben. Leider ging dabei das Password im Klartext über das Netz, was natürlich unverantwortlich ist.

Nun hat man also stattdessen ssh und es funktioniert recht ähnlich wie damals telnet, kann aber gleich noch sehr viel mehr, auch wesentlich mehr als ich hier in ein paar Zeilen schreiben kann. Wichtig ist nicht nur, daß man das Password verschlüsselt überträgt, sondern auch, daß man sicherstellt, daß die Gegenseite wirklich der gewünschte Rechner ist, sonst kan ein „man in the middle“ das Password abfangen und man ist wieder da, wo wir mit telnet standen.

Dazu gibt es im .ssh-Verzeichnis diese Zeritifikate, also solche Dateien wie id_rsa und id_rsa.pub. Die id_rsa sollte man hüten wie seinen Augapfel, da die Sicherheit des ganzen Protokolls davon abhängt. Mit ssh-keygen kann man sich solche Zertifikate auch anlegen, wahlweise auch so, daß man bei deren Verwendung ein Password eingeben muß (das nur auf dem lokalen Rechner bleibt). Die Zertifikate haben sogenannte „Fingerprints“, die man sich mit ssh-keygen -l anzeigen lassen kann. Genau dieser Fingerprint wird beim ersten mal angezeigt und man muß ihn bestätigen. Man sollte diesen also auf einem sicheren Kanal vorher überprüfen, daß er auch wirklich stimmt, zum Beispiel wenn man zwischen zwei Rechnern in einem verkabelten Netz, dem man traut, aufeinander zugreift, oder indem an sich den Fingerprint notiert oder ausdruckt. Wenn man ihn einmal bestätigt hat, wird er in .ssh/known_hosts eingetragen und man kann dort natürlich auch aufräumen, indem man unnötige Einträge löscht. Oder sogar mit USB-Stick übertragene Fingerprints reineditieren, wenn man das Format verstanden hat. Solange known_hosts keine falschen Einträge enthält, hat ein „man in the middle“ es sehr schwer und das Verfahren bietet eine vernünftige Sicherheit.

Nun läßt sich der „public key“ aus id_rsa.pub des eigenen Rechners in .ssh/authorized_keys des Rechners, auf dem man sich einloggen will, eintragen. Damit erreicht man, daß das ohne Password-Abfrage möglich ist, außer das lokale Zertifikat braucht eine Password-Abfrage. Die kann man aber auch einmalig pro Session mittels ssh-add durchführen.

ssh wird auch für andere Zwecke verwendet, weil man andere Protokolle darüber tunneln kann, z.B. Subversion oder git.

Sehr schön ist es auch, wenn man unter X11 ein

ssh -X user@host

aufruft. Dann kann man auf dem entfernten Rechner grafische Applikationen starten und das Display wird über den ssh-Tunnel umgeleitet.

Display umleiten ist in der Unix- und Linux-Welt schon seit über 25 Jahren gängige Praxis, aber mit ssh geht es nun auch sicherer als mit den unverschlüsselten Protokollen, die man damals gerne verwendet hat. Wer kennt noch xhost +?

Diese Überlegungen beziehen sich auf ssh unter Linux, gelten aber auch für alle möglichen Unix-Systeme, wie z.B. Solaris. Auf MS-Windows-Rechnern gibt es putty als verbreitete SSH-Client-Implementierung. Mit Putty findet man sicher vieles von dem wieder, was das Linux/Unix ssh kann, nur in etwas anderer Verpackung. Ich bevorzuge aber auf MS-Windowsrechnern cygwin und dessen ssh-Implementierung, die sehr ähnlich funktioniert. Es ist sogar möglich, mit cygwin einen ssh-Server aufzusetzen. Allerdings ist der Vorgang nicht ganz einfach.

Share Button

MS-Windows-Bug oder Feature mit CMD

English

Jeder der mit MS-Windows-Rechnern zu tun hat, kennt diese schwarzen Fenster, mit dem cmd-Kommamdozeileninterpreter, wenn auch kaum jemand sie mag. Die Unix- und Linux-Leute mögen sie nicht, weil cmd einfach verglichen mit typischen Linux- und Unix-Shells lächerlich wenig kann und die MS-Windows-Leute wollen nicht in der Kommandozeile arbeiten, jedenfalls nicht in dieser. Es gibt Alternativen wie Powershell und cygwin mit bash, aber das schwarze Fenster wird doch meist mit cmd assoziiert. Unter Linux gibt es auch solche Fenster für die Shell, z.B. xterm, aber dort sind sie meistens weiß. Dabei kann man auf beiden Systemen die Farben konfigurieren, wie man will.

NT-basierende MS-Windows-Systeme (NT 3.x, 4.x, 2000, XP, Vista, 7, 8, 10) haben jeweils verschiedene Subsysteme und Programme laufen in diesen Subsystemen, z.B. Win64, Win32, Win16, cygwin, DOS. Weil nun Programme für das DOS-Subsystem typischerweise im CMD-Fenster gestartet wurden und einige der Kommandos, die im CMD angeboten werden, ihren gleichnamigen Vorläufern aus der DOS-Ära von vor 30 Jahren nachempfunden wurden, wurde dieses CMD-Fenster früher (und vielleicht gelegentlich noch heute) oft fälschlicherweise als DOS-Fenster bezeichnet. Dabei kommt dieses schwarze Fenster eigentlich in vielen Situationen zum Vorschein, wenn z.B. ein Win32-Programm gestartet wird, das Ein- und Ausgabe (stdin, stdout, stderr) hat. Wenn diese umgeleitet sind, z.B. in eine Datei oder an ein anderes Programm, kann das Programm unsichtbar ohne schwarzes Fenster starten und gegebenenfalls graphisch in Erscheinung treten. Wenn es keine Umleitung der Ausgabe gibt, wird dem Programm ein solches schwarzes Fenster für die Anzeige der Ausgabe automatisch zur Verfügung gestellt. Und eines dieser Programme mit stdin und stdout ist nun einmal cmd, deshalb wird beim starten von cmd das schwarze Fenster drumherum dazu geliefert. Unter Linux (und Unix mit X11) ist es umgekehrt, man startet xterm bekommt darin die übliche Shell, außer man gibt explizit an, dass etwas anderes darin gestartet werden soll.

Nun empfehle ich einmal ein kleines Experiment. Wir brauchen dazu einen beliebigen graphischen Editor wie z.B. emacs, gvim, ultraedit, textpad, scite, es darf sogar notepad sein. Und ein cmd-Fenster.

  • Diese Befehle abschreiben nicht mit Copy&Paste übertragen.
  • Im cmd-Fenster mit cd in ein Verzeichnis wechseln, in dem Dateien angelegt werden können (Schreibrecht), falls nötig..
  • echo "xäöüx" > filec.txt
  • Die dabei angelegte Datei filec.txt mit dem graphischen Editor öffnen. Wie sehen die Umlaute aus??
  • Mit dem Editor im selben Verzeichnis eine neue Datei fileg.txt anlegen, die etwa folgende Zeile enthält: yäöüy.
  • Im CMD-Fenster diese ausgeben:
  • type fileg.txt
  • Wie sehen jetzt die Umlaute aus?

Es ist ein Feature oder ein Fehler aller gängigen MS-Windows-Versionen, dass diese schwarzen Fenster in der Standardeinstellung die Umlaute auf andere Positionen legen als die graphischen Editoren. Vielleicht weiß jemand, wie man das ändern kann, es würde mich interessieren.

Was ist hier genau passiert? Als die ersten DOS-Versionen Anfang der 1980er-Jahre aufkamen, gab es nur einen halbwegs etablierten Standard für Zeichensatzcodierungen, das war ASCII oder ISO-646-IRV, was immerhin ein großer Fortschritt gegenüber EBCDIC war. Aber dieser normierte nur die unteren 128 Zeichen (7 Bit) und enthielt keine Umlaute oder in Varianten Umlaute statt „irrelevanter“ Zeichen wie „@“, „[„, „~“ u.s.w. So fingen Hersteller und Softwaresysteme an, für die oberen 128 Plätze im Zeichensatz ihre eigene Lösungen zu erfinden. Commodore, Atari, MS-DOS, Apple, NeXT, TeX und überhaupt „alle“ hatten im Laufe der Jahre ihre „Lösungen“ für verschiedene Sprachregionen gefunden, die natürlich jeweils inkompatibel miteinander waren, meist sogar noch zwischen verschiedenen Produktgenerationen oder Ländereinstellungen desselben Herstellers inkompatibel. In Zeiten, wo man sowieso noch kaum Netzwerke hatte, wo es auch eine Sammlung von verschiedenen herstellerspezifischen Formaten für Disketten und herstellerspezifische Netzwerktechnologien gab, fiel das noch nicht so auf. Aber relativ früh wurde es bei X11 (dem gängigen graphischen System für Unix und Linux) üblich, Standardzeichensätze aus der ISO-8859-x-Familie oder später sogar Unicode mit utf-8 und utf-16 zu unterstützen. Linux hat schon in den 0.99-Versionen auch ohne graphische Oberfläche diese ISO-8859-1-Zeichensätze verwendet und nie versucht, seine eigene Zeichensatzcodierung zu erfinden.

Inzwischen sind wohl alle relevanten Systeme auf zum Unicode-Standard kompatible Zeichensatzcodierungen wie ISO-8859-x, utf-8 und utf-16 umgeschwenkt. Aber MS-Windows hat dies nur teilweise umgesetzt. Während das graphische System nur die modernen Codierungen verwendet oder zumindest mit Cp1252 dem recht nahe kommt, hat man für das textbasierte System (schwarze Fenster wie bei cmd) die Codierungen aus der DOS-Zeit von vor über 30 Jahren, wie z.B. Cp850 beibehalten und so einen Bruch innerhalb des System in Kauf genommen, der sehr ärgerlich ist, wenn man mit Daten mit Umlauten in cygwin oder cmd-Fenstern arbeiten will.

Wenn man mutig ist, kann man dieses Verhalten in der Registry ändern. Man muss dazu in HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\CodePage die Einträge OEMCP und OEMHAL gleichzeitig ändern. Einer ist für die Eingabe und einer für die Ausgabe zuständig, wenn man die also nicht gleichzeitig ändert, wird es sogar innerhalb des schwarzen Fensters inkonsistent. Sucht man danach im Internet, finden sich Beispiele, wo jemand versucht haben will, utf-8 (CP65001) einzustellen und das Ergebnis war, dass er nicht mehr booten konnte. Ich habe nicht überprüft, ob das manipulierte Behauptungen sind, um einer beliebten Firma zu schaden, oder ob es reale Erfahrungen sind. Man kann es mit Virtualisierung relativ risikofrei probieren, indem man sich ein funktionierendes System kopiert und es mit der Kopie testet. Auf jeden Fall ist das Editieren in der Registry nicht ganz risikofrei und geschieht „auf eigene Gefahr“…. Und in vielen Umgebungen ist es nicht möglich, weil die Berechtigungen dafür nicht ausreichen. Man kann es noch mit chcp im schwarzen Fenster selber ändern, vielleicht muss man dort auch noch so etwas wie chhal oder so eingeben, damit der Font passend zur Eingabe codiert ist.

Ob man das als „Bug“ oder lieber wegen der Kompatibilität zu älteren Versionen bis 30 Jahre zurück als Feature bezeichnen sollte, überlasse ich dem Leser.

Share Button

Wo bleiben die Transaktionen bei den NoSQL-Datenbanken?

Jetzt war mal wieder so ein Vortrag bei einer der vielen User-Groups, in der ich drin bin. Diesmal ging es um Riak und der Vortrag war von einem der Entwickler und war wirklich gut. Ein Stück weit wurde die Grundsatzthematik der NoSQL-Datenbanken behandelt, wobei natürlich Riak im Zentrum stand.

Während es bei den SQL-Datenbanken vielleicht etwa vier gibt, die einigermaßen austauschar sind, was die Funktionalität betrifft (Oracle, MS-SQL-Server, DB2 und PostgreSQL, mit Einschränkungen auch mySQL und MariaDB), ist hier die Frage relevant, das richtige Werkzeug für die richtige Aufgabe zu verwenden. Und das richtige Werkzeug sind oft die relationalen transaktionalen Datenbanken. Die Austauschbarkeit der relationalen Datenbankprodukte gilt natürlich nur, wenn man eine neue Applikation entwickelt, nicht wenn man Software nachträglich umschreiben muß und die Datenbankadministrationsprozesse nachträglich ändern muß.

Nun sind die Daten ja immer sehr wichtig, sonst könnte man sich den Aufwand ja sparen, sie zu speichern. Und wenn die Datenbank nicht transaktional ist, dann ist das gruselig, weil die Daten nicht zuverlässig und nicht genau genug gespeichert werden. Das Versprechen der transaktionalen Datenbanken für Transaktionen wird ja kurz mit „ACID“ bezeichnet:

  • „Atomic“ bedeutet, daß die Transaktion entweder komplett oder gar nicht ausgeführt wird
  • „Consistent“ bedeutet, daß die Daten immer in einem konsistenten Zustand sind.
  • „Isolated“ bedeutet, daß verschiedene gleichzeitig laufende Transaktionen sich nicht gegenseitig beeinflussen.
  • „Durability“ bedeutet, daß die Daten nach Abschluß der Transaktion garantiert dauerhaft gespeichert sind.

Super, da kann nichts mehr schiefgehen. Und Software von Oracle oder IBM ist serienmäßig komplett fehlerfrei, von Microsoft sowieso und bei PostgreSQL bauen die Entwickler der Software, die die Datenbank verwendet, allfällige Fehler der DB-Software selbst noch kurz in der Nacht aus… Aber fairerweise muß man sagen, daß die Kernfunktionalität der Datenbankprodukte tatsächlich recht zuverlässig funktioniert und die nervigen Fehler eher am Rande bei unwichtigen Dingen wie Installern oder Security-Features aufgetreten sind, die hier nicht das Thema sind. 😉

Also gut, man kann also mal annehmen, daß die DB-Software vernünftige Zuverlässigkeit hat. Was ist mit der Hardware? In einem großen Rechenzentrum muß rein rechnerisch immer irgendwo ein Hardwaredefekt sein. Ist aber kein Problem, man baut die Hardware und damit die Datenbankinstallation einfach redundant auf. Und es gibt tolle Mechanismen, die mit erheblichem Aufwand sicherstellen, daß ACID immer noch gilt. Man hat also eine Datenbank, die auf mehreren Rechnern läuft und sich gegen außen wie einer verhält. Eine Transaktion kann auch mehrere dieser Rechner involvieren. Egal was passiert, soll immer ACID-Transaktionalität gelten. Mit „Two-Phase-Commit“ und solchen Werkzeugen kann man das hinbekommen. Zumindest sagt man, daß es in der Praxis zuverlässig funktioniert. Vielleicht bis zu einer gewissen Größe, denn wenn eine einzige Datenbank ein ganzes großes Rechenzentrum beansprucht, kann man sich sicher auf einen hohen Stromverbrauch verlassen, aber mehr will ich dazu hier nicht sagen. Reale Rechenzentren, die transaktionale Datenbanken betreiben, haben erfahrungsgmäß auch viele mehr oder weniger unabhängige Datenbanken am Laufen.

Man kann also mit recht großen ACID-transaktionalen Datenbanken die Unzuverlässigkeit der Hardware recht gut in den Griff bekommen. Das ist nicht billig und es lohnt sich gute Datenbankberater heranzuziehen.

Wie sieht es mit der Applikationssoftware aus? Die wird heutzutage ja oft in Java geschrieben und läuft deshalb in der Sandbox, was ja alle Probleme verhindert, weil die Sandbox unterbindet, daß irgendwas gefährliches gemacht wird… 😉

Ist die Applikationssoftware fehlerfrei? Oder zumindest so fehlerfrei, daß nie mit den Daten etwas schief gehen kann? Vielleicht, wenn man optimistisch ist? Wenn wir schon bis hierher Optimismus aufbauen konnten… Die transaktionale Datenbank ist ein nütziches Werkzeug, wenn man sie mit hinreichend korrekter Software benutzt. Aber das machen wir alle und auf dem Laptop des Entwicklers hat es wirklich funktioniert, es sind halt die Benutzer schuld, die mehrere Requests gleichzeitig abschicken. Was ist mit dem „I“ aus ACID passiert? Ja, die Datenbank macht es schon richtig, aber die Applikation stürzt ab oder erzeugt korrumpierte Daten. Oder verwendet zu kleine oder zu große Transaktionen. Schade…

Nun kommt aber noch die Software- und Systemarchitektur ins Spiel. Man fängt an, ein großes System über mehrere Server zu verteilen, Caching wird verwendet, Teilbereiche der Daten werden über Services angesprochen. Natürlich arbeitet man mit tollen Frameworks und die Datenbank ist für den Applikationsentwickler schon recht weit weg, aber immer noch macht man irgendwo implizit oder explizit schöne Tranaktionen auf und beendet sie mit commit oder rollback. Niemand weiß mehr, in welcher Schachtelungsteiefe von solchen Methoden, die implizit Transaktionen durchführen, man sich befindet und mit bestimmten Mustern kann man das aus Versehen austricksen, aber so etwas passiert natürlich nicht. Wie sieht es jetzt mit ACID aus?

Kurz gesagt, für reale Applikationen muß man genauer hinschauen, ob ein etas schwächeres Modell als ACID wirklich ein Nachteil ist.

Nun muß man aber noch einmal auf den Ausgangspunkt zurückkommen. Transaktionen lassen sich sehr gut für nicht-relationale Datenkbanken definieren und auch implementieren. Umgekehrt kann man für manche Zwecke durchaus relationale SQL-Datenbanken verwenden, die nicht transaktional sind. Oder man hat wie bei MongoDB Transaktionen für einzelne DB-Operationen, kann diese aber nicht zusammenfassen.

Share Button

MongoDB im RAM

Hier ist eine interessante Beschreibung, wie man MongoDB (unter Linux) komplett im RAM betreiben kann:

How to use MongoDB as a pure in-memory DB (Redis style)

Die Idee ist einfach und interessant, weil sie sich auch für viele andere, ähnlich gelagerte Anwendungsfälle eignet.

Für die Entwicklung von Mongo-DB-basierenden Applikationen und vor allem für die Unit-Tests kann das auch eine sehr nützliche Sache sein.

Share Button

Responsive Design

Neu ist dieser Blog mit „responsive design“ ausgestattet. Das bedeutet, daß das Layout sich von selber kleinere Bildschirme von Mobiltelefonen anpaßt.

Auch die Seite IT Sky Consulting GmbH hat responsive Design. Dies ist nur mit CSS umgesetzt, die HTML-Seiten existieren nur einmal.

Share Button