Kopiermodus optimieren

WebSphere eXtreme Scale erstellt eine Kopie des Werts auf der Basis einer der verfügbaren CopyMode-Einstellungen. Legen Sie fest, welche Einstellung sich am besten für Ihre Implementierungsanforderungen eignet.

Sie können die Methode setCopyMode(CopyMode, valueInterfaceClass) der API BackingMap verwenden, um den Kopiermodus auf eines der folgenden Felder des Typs "final static" setzen, die in der Klasse com.ibm.websphere.objectgrid.CopyMode definiert sind.

Wenn eine Anwendung die Schnittstelle ObjectMap verwendet, um eine Referenz auf einen Map-Eintrag anzufordern, verwenden Sie diese Referenz nur in der Datengridtransaktion, in der die Referenz angefordert wurde. Wenn Sie die Referenz in einer anderen Transaktion verwenden, kann dies Fehler zur Folge haben. Bei der Verwendung der pessimistischen Sperrstrategie für die BackingMap wird beispielsweise über einen Aufruf der Methode "get" oder "getForUpdate" je nach Transaktion eine S- (gemeinsame) bzw. U-Sperre (Aktualisierung) angefordert. Die Methode "get" gibt die Referenz auf den Wert zurück, und die angeforderte Sperre wird freigegeben, sobald die Transaktion abgeschlossen ist. Die Transaktion muss die Methode "get" oder "getForUpdate" aufrufen, um den Map-Eintrag in einer anderen Transaktion zu sperren. Jede Transaktion muss eine eigene Referenz auf den Wert über die Methode get bzw. getForUpdate anfordern, anstatt dieselbe Wertreferenz einer anderen Transaktion wiederzuverwenden.

CopyMode-Einstellung für Entitäts-Maps

Wenn Sie eine Map verwenden, die einer Entität der API EntityManager zugeordnet ist, gibt die Map immer die Tupelobjekte der Entität wieder, ohne eine Kopie zu erstellen, sofern Sie nicht den Kopiermodus COPY_TO_BYTES verwenden. Es ist wichtig, dass die CopyMode-Einstellung aktualisiert wird bzw. das Tupel entsprechend kopiert wird, wenn Änderungen vorgenommen werden.

COPY_ON_READ_AND_COMMIT

Der Modus COPY_ON_READ_AND_COMMIT ist der Standardmodus. Das Argument "valueInterfaceClass" wird ignoriert, wenn dieser Modus verwendet wird. Dieser Modus stellt sicher, dass eine Anwendung keine Referenz auf das Wertobjekt enthält, das in der BackingMap enthalten ist. Stattdessen arbeitet die Anwendung immer mit einer Kopie des Werts, der in der BackingMap enthalten ist. Der Modus COPY_ON_READ_AND_COMMIT stellt sicher, dass die Anwendung die Daten, die in der BackingMap zwischengespeichert sind, nicht unabsichtlich beschädigen kann. Wenn eine Anwendungstransaktion eine Methode " ObjectMap.get" für einen bestimmten Schlüssel aufruft und es sich um den ersten Zugriff auf den ObjectMap-Eintrag für diesen Schlüssel handelt, wird eine Kopie des Werts zurückgegeben. Beim Festschreiben der Transaktion werden alle von der Anwendung festgeschriebenen Änderungen in die BackingMap kopiert, um sicherzustellen, dass die Anwendung keine Referenz auf den festgeschriebenen Wert in der BackingMap hat.

COPY_ON_READ

Der Modus COPY_ON_READ bietet im Vergleich mit dem Modus COPY_ON_READ_AND_COMMIT eine bessere Leistung, weil in diesem Modus beim Festschreiben einer Transaktion keine Daten kopiert werden. Das Argument "valueInterfaceClass" wird ignoriert, wenn dieser Modus verwendet wird. Zur Bewahrung der Integrität der BackingMap-Daten stellt die Anwendung sicher, dass jede Referenz auf einen Eintrag gelöscht wird, wenn die Transaktion festgeschrieben wird. In diesem Modus gibt die Methode "ObjectMap.get" eine Kopie des Werts an Stelle einer Referenz auf den Wert zurück, um sicherzustellen, dass Änderungen, die von der Anwendung am Wert vorgenommen werden, solange keine Auswirkungen auf den BackingMap-Wert haben, bis die Transaktion festgeschrieben wird. Beim Festschreiben der Transaktion wird jedoch keine Kopie der Änderungen erstellt. Stattdessen wird die Referenz auf die Kopie, die von der Methode "ObjectMap.get" zurückgegeben wurde, in der BackingMap gespeichert. Die Anwendung löscht alle Referenzen auf Map-Einträge, wenn die Transaktion festgeschrieben wird. Wenn die Anwendung die Referenzen auf die Map-Einträge nicht löscht, kann die Anwendung die in der BackingMap zwischengespeicherten Daten beschädigen. Falls eine Anwendung diesen Modus verwendet und Probleme auftreten, wechseln Sie in den Modus COPY_ON_READ_AND_COMMIT, um festzustellen, ob die Probleme weiterhin auftreten. Sollten die Probleme nicht mehr auftreten, ist dies ein Hinweis darauf, dass die Anwendung nach dem Festschreiben der Transaktion nicht alle Referenzen löscht.

COPY_ON_WRITE

Der Modus COPY_ON_WRITE bietet im Vergleich mit dem Modus COPY_ON_READ_AND_COMMIT eine bessere Leistung, weil in diesem Modus beim ersten Aufruf der Methode "ObjectMap.get" für einen bestimmten Schlüssel in einer Transaktion keine Daten kopiert werden. Die Methode "ObjectMap.get" gibt einen Proxy auf den Wert an Stelle einer direkten Referenz auf das Wertobjekt zurück. Der Proxy stellt sicher, dass keine Kopie des Werts erstellt wird, sofern die Anwendung nicht eine Methode "set" für die Wertschnittstelle aufruft, die mit dem Argument "valueInterfaceClass" angegeben wurde. Der Proxy verwendet eine Implementierung von "copy on write" (Kopieren beim Schreiben). Wenn eine Transaktion festgeschrieben wird, prüft die BackingMap den Proxy, um festzustellen, ob auf die aufgerufene Methode "set" hin eine Kopie erstellt wurde. Wurde eine Kopie erstellt, wird diese Referenz auf die Kopie in der BackingMap gespeichert. Dieser Modus hat den großen Vorteil, dass beim Lesen oder Festschreiben niemals ein Wert kopiert wird, wenn die Transaktion keine Methode "set" aufruft, um den Wert zu ändern.

In den Modi COPY_ON_READ_AND_COMMIT und COPY_ON_READ wird eine tiefe Kopie erstellt, wenn ein Wert aus der ObjectMap abgerufen wird. Wenn eine Anwendung nur einige der Werte, die in einer Transaktion abgerufen werden, aktualisiert, ist dieser Modus nicht optimal. Der Modus COPY_ON_WRITE unterstützt dieses Verhalten zwar effizient, erfordert aber, dass die Anwendung ein einfaches Muster verwendet. Die Wertobjekte sind erforderlich, um eine Schnittstelle zu unterstützen. Die Anwendung muss die Methoden in dieser Schnittstelle verwenden, wenn sie mit dem Wert in einer Sitzung interagiert. In diesem Fall werden Proxys für die Werte erstellt, die an die Anwendung zurückgegeben werden. Der Proxy hat eine Referenz auf den echten Wert. Wenn die Anwendung nur Leseoperationen durchführt, werden diese immer mit der echten Kopie durchgeführt. Wenn die Anwendung ein Attribut im Objekt ändert, erstellt der Proxy eine Kopie des realen Objekts und ändert dann die Kopie. Von diesem Zeitpunkt an verwendet der Proxy die Kopie. Mit der Verwendung der Kopie kann die Kopieroperation für Objekte, die von der Anwendung nur gelesen werden, vollständig umgangen werden. Alle Änderungsoperationen müssen mit dem festgelegten Präfix beginnen. Enterprise JavaBeans werden normalerweise so codiert, dass sie diese Art der Methodenbenennung für Methoden verwenden, die die Objektattribute ändern. Diese Konvention muss eingehalten werden. Alle geänderten Objekte werden zu dem Zeitpunkt kopiert, zu dem sie von der Anwendung geändert werden. Dieses Lese- und Schreibszenario ist das effizienteste Szenario, das von eXtreme Scale unterstützt wird. Wenn Sie den Modus COPY_ON_WRITE für eine Map konfigurieren möchten, können Sie das folgende Beispiel verwenden. In diesem Beispiel speichert die Anwendung Person-Objekte, die in der Map mit dem Namen als Schlüssel verwaltet werden. Das Person-Objekt wird im folgenden Code-Snippet dargestellt.

class Person {
    String name;
    int age;
    public Person() {
    }
    public void setName(String n) 	{
        name = n;
    }
    public String getName() {
        return name;
    }
    public void setAge(int a) {	
        age = a;
    }
    public int getAge() {
        return age;
    }
}

Die Anwendung verwendet die Schnittstelle "IPerson" nur, wenn sie mit Werten interagiert, die aus einer ObjectMap abgerufen werden. Ändern Sie das Objekt, wie im folgenden Beispiel gezeigt, um eine Schnittstelle zu verwenden:

interface IPerson
{
    void setName(String n);
    String getName();
    void setAge(int a);
    int getAge();
}
// Person-Objekt ändern, um die Schnittstelle "IPerson" zu implementieren.
class Person implements IPerson {
    ...
}

Anschließend muss die Anwendung, wie im folgenden Beispiel gezeigt, den Modus COPY_ON_WRITE für die BackingMap konfigurieren:
ObjectGrid dg = ...;
BackingMap bm = dg.defineMap("PERSON");
// COPY_ON_WRITE für diese Map mit
// IPerson als valueProxyInfo-Klasse verwenden.
bm.setCopyMode(CopyMode.COPY_ON_WRITE,IPerson.class);
// Anschließend muss die Anwendung das folgende Muster verwenden,
// wenn die Map PERSON verwendet wird.
Session sess = ...;
ObjectMap person = sess.getMap("PERSON");
...
sess.begin();
// Die Anwendung setzt den zurückgegebenen Wert in IPerson und nicht in Person um.
IPerson p = (IPerson)person.get("Billy");
p.setAge( p.getAge() + 1 );
...
// Neues Person-Objekt erstellen und der Map hinzufügen
Person p1 = new Person();
p1.setName("Bobby");
p1.setAge(12);
person.insert(p1.getName(), p1);
sess.commit();
// Das folgende Snippet funktioniert nicht. Es löst eine Ausnahme
// des Typs "ClassCastException" aus.
sess.begin();
// Der Fehler ist hier, dass Person an Stelle von
// IPerson verwendet wird.
Person a = (Person)person.get("Bobby");
sess.commit();
Der erste Abschnitt der Anwendung ruft einen Wert ab, der in der Map den Namen Billy hat. Die Anwendung setzt den zurückgegebenen Wert in das IPerson-Objekt und nicht in das Person-Objekt um, weil der zurückgegebene Proxy zwei Schnittstellen implementiert:
  • die im Aufruf der Methode BackingMap.setCopyMode angegebene Schnittstelle,
  • Schnittstelle com.ibm.websphere.objectgrid.ValueProxyInfo

Sie können den Proxy in zwei Typen umsetzen. Der letzte Teil des vorherigen Code-Snippets demonstriert, was im Modus COPY_ON_WRITE nicht zulässig ist. Die Anwendung ruft den Datensatz "Bobby" ab und versucht, den Datensatz in ein Person-Objekt umzusetzen. Diese Aktion scheitert mit einer Ausnahme bei Klassenumsetzung, weil der zurückgegebene Proxy kein Person-Objekt ist. Der zurückgegebene Proxy implementiert das IPerson-Objekt und ValueProxyInfo.

Schnittstelle "ValueProxyInfo" und Unterstützung von Teilaktualisierungen: Diese Schnittstelle ermöglicht einer Anwendung, den festgeschriebenen schreibgeschützten Wert , der vom Proxy referenziert wird, oder die Gruppe der Attribute, die in dieser Transaktion geändert wurden, abzurufen.

public interface ValueProxyInfo {
    List /**/ ibmGetDirtyAttributes();
    Object ibmGetRealValue();
}

Die Methode ibmGetRealValue gibt eine schreibgeschützte Kopie des Objekts zurück. Die Anwendung darf diesen Wert nicht ändern. Die Methode ibmGetDirtyAttributes gibt eine Liste mit Zeichenfolgen zurück, die die Attribute darstellen, die von der Anwendung während dieser Transaktion geändert wurden. Der Hauptanwendungsfall für die Methode ibmGetDirtyAttributes ist in einem JDBC- (Java Database Connectivity) oder CMP-basierten Loader. Nur die in der Liste benannten Attribute müssen in der SQL-Anweisung bzw. in dem Objekt, das der Tabelle zugeordnet ist, aktualisiert werden. Dies führt zu einer effizienteren SQL. die vom Loader generiert wird. Wenn eine Copy-on-Write-Transaktion festgeschrieben wird und ein Loader integriert ist, kann der Loader die Werte der geänderten Objekte in die Schnittstelle ValueProxyInfo umsetzen, um diese Informationen abzurufen.

Behandlung der Methode "equals", wenn COPY_ON_WRITE oder Proxys verwendet werden: der folgende Code erstellt beispielsweise ein Person-Objekt und fügt es anschließend in eine ObjectMap ein. Anschließend ruft er dasselbe Objekt mit der Methode "ObjectMap.get" ab. Der Wert wird in die Schnittstelle umgesetzt. Wenn der Wert in die Schnittstelle "Person" umgesetzt wird, wird eine Ausnahme des Typs "ClassCastException" ausgelöst, weil der zurückgegebene Wert ein Proxy ist, der die Schnittstelle "IPerson" implementiert und kein Person-Objekt ist. Die Gleichheitsprüfung scheitert, wenn die Operation "==" verwendet wird, weil es sich nicht um dasselbe Objekt handelt.

session.begin();
// Neues Person-Objekt
Person p = new Person(...);
personMap.insert(p.getName, p);
// Erneut abrufen und daran denken, die Schnittstelle für die Umsetzung zu verwenden
IPerson p2 = personMap.get(p.getName());
if(p2 == p) {
    // Objekte sind identisch
} else {
    // Objekte sind nicht identisch
}

Ein weiterer Aspekt ist das Überschreiben der Methode "equals". Die equals-Methode muss sicherstellen, dass das Argument ein Objekt ist, das die Schnittstelle IPerson implementiert, und das Argument in ein IPerson-Objekt umsetzen. Da das Argument ein Proxy sein kann, das die Schnittstelle IPerson implementiert, müssen Sie die Methoden getAge und getName verwenden, wenn Sie vergleichen, ob die Instanzvariablen identisch sind. Sehen Sie sich das folgende Beispiel an:

{
    if ( obj == null ) return false;
    if ( obj instanceof IPerson ) {
        IPerson x = (IPerson) obj;
        return ( age.equals( x.getAge() ) && name.equals( x.getName() ) )
    }
    return false;
}

Voraussetzungen für die Konfiguration von ObjectQuery und HashIndex: Wenn Sie COPY_ON_WRITE mit ObjectQuery- oder HashIndex-Plug-ins verwenden, müssen Sie das Schema ObjectQuery und das HashIndex-Plug-in für den Zugriff auf die Objekte mit Eigenschaftenmethoden konfigurieren (Standardeinstellung). Wenn Sie den Feldzugriff konfiguriert haben, versuchen die Abfrageengine und der Index, auf die Felder im Proxy-Objekt zuzugreifen. Daraufhin wird immer null (0) zurückgegeben, da die Objektinstanz ein Proxy ist.

NO_COPY

Der Modus NO_COPY ermöglicht einer Anwendung, Leistungsverbesserungen zu erzielen, erfordert dafür aber, dass die Anwendung Objektwerte, die mit einer Methode ObjectMap.get abgerufen werden, nicht ändert. Das Argument valueInterfaceClass wird ignoriert, wenn dieser Modus verwendet wird. Wenn dieser Modus verwendet wird, wird keine Kopie des Werts erstellt. Wenn die Anwendung Instanzen von Wertobjekten ändert, werden die Daten in der BackingMap beschädigt. Der Modus NO_COPY ist hauptsächlich für schreibgeschützte Maps hilfreich, in denen die Daten von der Anwendung nie geändert werden. Falls eine Anwendung diesen Modus verwendet und Probleme auftreten, wechseln Sie in den Modus COPY_ON_READ_AND_COMMIT, um festzustellen, ob die Probleme weiterhin auftreten. Sollten die Probleme nicht mehr auftreten, ist dies ein Hinweis darauf, dass die Anwendung während der Transaktion oder nach dem Festschreiben der Transaktion den von der Methode "ObjectMap.get" zurückgegebenen Wert ändert. Alle Maps, die Entitäten der API EntityManager zugeordnet sind, verwenden diesen Modus automatisch, unabhängig davon, welcher Modus in der Konfiguration von eXtreme Scale definiert ist.

Alle Maps, die Entitäten der API EntityManager zugeordnet sind, verwenden diesen Modus automatisch, unabhängig davon, welcher Modus in der Konfiguration von eXtreme Scale definiert ist.

COPY_TO_BYTES

Sie können Objekte in einem serialisierten Format an Stelle des POJO-Formats speichern. Mit der Einstellung COPY_TO_BYTES können Sie den Speicherbedarf eines großen Objektgraphen verringern. Weitere Informationen finden Sie unter Leistung mit Bytefeldgruppen-Maps verbessern.

COPY_TO_BYTES_RAW

Mit COPY_TO_BYTES_RAW, können Sie direkt auf die serialisierte Form Ihrer Daten zugreifen. Dieser Kopiermodus ist eine effiziente Methode für die Interaktion mit serialisierten Bytes, die Ihnen ermöglicht, den Entserialisierungsprozess beim Zugriff auf Objekte im Hauptspeicher zu umgehen.

Sie können den Kopiermodus in der ObjectGrid-XML-Deskriptordatei auf COPY_TO_BYTES und in den Instanzen, in denen Sie auf die unbearbeiteten, serialisierten Daten zugreifen möchten, über das Programm auf COPY_TO_BYTES_RAW setzen. Setzen Sie den Kopiermodus in der ObjectGrid-XML-Deskriptordatei nur dann auf COPY_TO_BYTES, wenn Ihre Anwendung die Rohdaten im Rahmen des Hauptanwendungsprozesses verwendet.

Unzulässige Verwendung von CopyMode

Es treten Fehler auf, wenn eine Anwendung versucht, die Leistung mit dem Kopiermodus COPY_ON_READ, COPY_ON_WRITE oder NO_COPY, wie zuvor beschrieben, zu verbessern. Diese Probleme treten nicht auf, wenn Sie den Kopiermodus in COPY_ON_READ_AND_COMMIT ändern.

Problem

Das Problem kann auf beschädigte Daten in der ObjectGrid-Map zurückzuführen sein, die das Ergebnis eines Verstoßes gegen den Programmiervertrag des verwendeten Kopiermodus durch die Anwendung sind. Fehlerhafte Daten können zu unvorhersehbaren Fehlern führen, die vorübergehend, unerklärlich oder unerwartet sein können.

Lösung

Die Anwendung muss den Programmiervertrag einhalten, der für den verwendeten Kopiermodus festlegt wurde. Für die Kopiermodi COPY_ON_READ und COPY_ON_WRITE verwendet die Anwendung eine Referenz auf ein Wertobjekt außerhalb des Transaktionsbereichs, von dem die Wertreferenz abgerufen wurde. Zur Verwendung dieser Modi muss die Anwendung die Referenz auf das Wertobjekt nach Abschluss der Transaktion löschen und eine neue Referenz auf das Wertobjekt in jeder Transaktion abrufen, die auf das Wertobjekt zugreift. Im Kopiermodus NO_COPY darf die Anwendung das Wertobjekt nie ändern. In diesem Fall müssen Sie die Anwendung so schreiben, dass sie das Wertobjekt nicht ändert, oder einen anderen Kopiermodus für die Anwendung festlegen.