2012-04-06 7 views
22

Conosco almeno due enhancer di codice byte che modificano il "modello oggetto" in fase di runtime per consentire l'esecuzione della transazione in modo trasparente. Uno di questi è parte di Versant VOD, che uso ogni giorno al lavoro e l'altro fa parte di Terracotta. Probabilmente ce ne sono molti altri, ad esempio in ORM, ma Versant si occupa di questo nella mia azienda.Esiste una API Java per il rilevamento/modifica delle versioni degli oggetti?

La mia domanda è: esiste una tale API open source che può essere utilizzata autonomamente, indipendentemente dal prodotto per cui è stata progettata? Potresti dire un'API "hackerabile". Dovrebbe solo tenere traccia delle modifiche , non leggere l'accesso, il che rallenterebbe significativamente il codice. In altre parole, non dovrebbe richiedere un blocco esplicito di lettura/scrittura. Ciò richiede l'accesso a tutte le classi che eseguono modifiche, non solo al modello di dati, o richiede di mantenere una qualche forma di "versione precedente" in memoria per fare un confronto.

Il problema che sto cercando di risolvere è che sono presenti grafici "grandi" (da 32K a 256K) che sono "serializzati" in un DB (NoSQL). Sono longevi e devono essere periodicamente ri-serializzati per avere una "storia" dei cambiamenti. Ma sono piuttosto costosi da serializzare e la maggior parte dei cambiamenti è minore.

Potrei serializzarli completamente ogni volta ed eseguire un binario diff sul flusso, ma questo suona molto intensivo della CPU. Una soluzione migliore sarebbe un'API che modifica le operazioni di scrittura sul modello per il protocollo delle modifiche, in modo che dopo l'iniziale "immagine" sia memorizzata, solo il protocollo deve essere memorizzato.

Ho trovato alcune domande che parlano di Apache Commons Beanutils per confrontare gli oggetti, ma che non è utile per le modifiche sul posto; Avrei bisogno di creare un clone completo del modello tra ogni "transazione commerciale".

Per reiterare, sto cercando un'API "in-memory", all'interno della stessa JVM, che non coinvolge alcuna applicazione server esterna. Le API che coinvolgono il codice nativo sono OK se sono disponibili su Win, Mac & Linux. L'API non deve essere correntemente impacchettata in modo indipendente; deve solo essere possibile estrarlo dal "progetto genitore" per formare un'API indipendente (la licenza del progetto genitore deve consentirlo).

I miei grafici di oggetti coinvolgeranno molti array di grandi dimensioni e pertanto devono essere supportati in modo efficiente.

Le modifiche non sono desiderate solo per il controllo, ma in modo che possano essere riprodotti o annullati. Più precisamente, con il grafico iniziale deserializzato e un elenco di modifiche, dovrei arrivare a un grafico finale identico. Inoltre, a partire dal grafico finale, dovrebbe essere possibile tornare al grafico iniziale applicando le modifiche al contrario. Questo utilizza esattamente la stessa funzionalità, ma richiede il protocollo di modifica per mantenere il vecchio valore in aggiunta al nuovo valore.

La licenza API deve essere compatibile con l'uso commerciale.

[EDIT] Finora non ho ricevuto risposta utile, e non mi sembra quello che voglio. Questo mi lascia con una sola opzione: fallo accadere. Inserirò un link qui come risposta quando ho un'implementazione funzionante, poiché questo è il prossimo passo nel mio progetto e non posso andare avanti senza di esso.

[EDIT] Ho trovato per caso questa domanda in qualche modo correlato: Is there a Java library that can "diff" two Objects?

+0

Non completamente sicuro di ciò che si sta cercando. Ma i suoi suoni sono analoghi alla sovversione. Se gli oggetti sono stati serializzati su un file, che è stato controllato in SVN, la cronologia delle modifiche sarà lì. Non molto utile se stai cercando un accesso programmatico alle modifiche. Di che cosa hai bisogno? – scorpdaddy

+0

LOL! Capisco cosa intendi, ma non si adatta affatto al mio caso d'uso. In primo luogo, dovrei essere tutti "in-memory", non basati su client-server, e in secondo luogo, tutti gli RCS sono intrinsecamente cattivi nei dati binari, che è quello che sto cercando di fare. Nessun XML o JSON coinvolti qui. Aggiornerò la domanda –

+0

Non conosco alcuna API di questo tipo, ma forse potresti pensare negli approcci di ordine. Invece di provare l'approccio API trasparente, sembra che sia effettivamente un requisito per la tua applicazione. È possibile memorizzare il grafico iniziale una volta e quindi creare un albero con le versioni e i nuovi dati. –

risposta

8

Kryo v1 ha un serializzatore che conosce gli ultimi dati serializzati e emette solo un delta. Durante la lettura, conosce gli ultimi dati ricevuti e applica il delta. Il delta viene eseguito a livello di byte. Here è il serializzatore . La maggior parte del lavoro è svolto da this class. Questo potrebbe essere usato in alcuni modi utili, ad esempio il networking simile a Quake 3.

Questo è stato omesso in Kryo v2 perché AFAIK non era mai stato messo in uso. Inoltre, non disponeva di una vasta serie di test. Potrebbe essere portato su e potrebbe fare ciò di cui hai bisogno o servire come base per ciò che ti serve.

Sopra anche pubblicato sui serializzatori JVM mailing list.

L'esecuzione a livello di oggetto sarebbe un po 'complicata. Potresti scrivere qualcosa di simile a FieldSerializer che percorre contemporaneamente due grafici di oggetti Questo sarebbe comunque un codice autonomo, non un serializzatore di Kryo. Ad ogni livello puoi chiamare uguale. Scrivi un byte in modo che quando leggi tu sappia che è uguale a Se non è uguale, usa Kryo per scrivere l'oggetto. Uguali sarebbero chiamati più volte per lo stesso oggetto, specialmente per oggetti profondamente annidati.

Un altro modo per eseguire questa operazione è eseguire solo gli scalari e le stringhe precedenti, ovvero solo i valori scritti dalla classe Output. Il problema è camminare su due grafici di oggetti. Per usare Kryo penso che dovresti duplicare tutti i serializzatori per conoscere l'altro grafico dell'oggetto.

Forse potresti usare Kryo con il tuo Output che raccoglie valori in un elenco invece di scriverli. Usalo per "serializzare" il tuo vecchio oggetto grafico. Ora scrivi un'altra versione del tuo Output che prende questo elenco e usalo per serializzare il tuo nuovo oggetto grafico. Ogni volta che viene scritto un valore, per prima cosa controllalo con l'oggetto successivo nella tua lista. Se uguale, scrivi 1. Se non è uguale, scrivi uno 0 e poi il valore.

Questo potrebbe essere reso più efficiente dallo spazio utilizzando la prima uscita due volte, una volta sulla vecchia e una volta sul nuovo grafico. Ora hai due liste di valori. Usali per scrivere una sequenza di bit che denota che sono uguali. Ciò consente di risparmiare spazio sulla scrittura di un intero byte per ogni valore, ma ha il sovraccarico di un elenco aggiuntivo. Infine, scrivi tutti i valori che non sono uguali.

Per completare questa idea, è necessario essere in grado di deserializzare i dati. Avrai bisogno di una tua versione della classe Input che tenga un elenco di valori dal vecchio oggetto grafico. L'input prima legge la bitstring (o un byte per valore). Per un valore uguale, restituisce il valore dall'elenco anziché leggere dai dati. Se un valore non è uguale, chiama il metodo super per leggere dai dati.

Non sono sicuro se questo sarebbe più veloce di farlo a livello di byte. Se dovessi indovinare, direi che probabilmente sarebbe più veloce. Memorizzando tutti i valori in una lista ci sarà un sacco di box/unboxing, e questo approccio assegna ancora tutti i campi anche se non sono stati modificati. Dubito che le prestazioni saranno un problema in entrambi i casi, quindi probabilmente sceglierei semplicemente l'approccio più semplice. Difficile dire quale sia questo ... resuscitare le cose delta o scrivere le proprie classi di Output/Input.

Se hai voglia di contribuire a Kryo, sarebbe ovviamente fantastico. :)

+0

Questa potrebbe essere la mia migliore scommessa. :) Ma per favore scrivi qualcosa anche qui, quindi i lettori SO non devono seguire il link. –

+0

Ho appena guardato di nuovo Kryo. L'avevo licenziato prima a causa della mancanza di strutture per l'archiviazione a lungo termine (evoluzione dello schema), ma V2 sembra risolverlo. :) –

+0

Aggiornato con alcune informazioni in più. TaggedFieldSerializer è il prossimo passo verso lo sviluppo di FieldSerializer. Dopo di che c'è CompatibleFieldSerializer. – NateS

1

Non so quali API, ma posso essere così complicato:

Una soluzione migliore sarebbe un'API che modificano scrivere le operazioni sul modello per il protocollo delle modifiche, in modo che dopo l'iniziale "immagine" è memorizzato, solo il protocollo deve essere memorizzato.

Direi che è necessario solo 2 componenti: Azione e ActionProcessor

Hai solo bisogno di persistere una lista (protocollo) di azioni eseguite.

interface ActionProcessor{ 
    void perform(Action action); 
    void undoToDate(Date date); 
} 

iterface Action{ 
    Date getDate(); 
    void perform(); 
    void undo(); 
}  
+2

Questo sarebbe l'approccio http://prevayler.org/. Mentre funzionerebbe, la quantità di codice necessaria per * manualmente * implementare le funzioni di annullamento per ogni azione sarebbe tremenda, il che comporterebbe molti bug, che comporterebbero il fallimento di un annullamento corretto. Questa sarebbe l'ultima soluzione, se tutto il resto fallisce. In secondo luogo, una volta introdotta una nuova versione del tuo codice, il tuo impl Action cambierebbe, causando una perdita di riproducibilità e "annullabilità", perché avresti registrato l'ID azione ei suoi parametri, invece del vero cambiamento. –

1

Per quanto ne so, Gemfire è un prodotto enterprise pietra preziosa (ora VmWare) facendo qualcosa di simile al Smalltalk OODB pietra preziosa, ma poi per Java. James Foster ha creato un series of videos su come funziona la pietra preziosa. Li ho trovati molto interessanti. Gemstone ha una versione gratuita per costruire piccoli sistemi (Seaside web) con.

2

Dai uno sguardo allo Content repository API for Java, è utilizzato da Artifactory per controllare le dipendenze Maven. Il Apache Jackrabbit è l'implementazione di riferimento di questo JSR (JSR-283 version 2)

+0

Questo è molto interessante. E dice questo: "Un altro tipo popolare è il tipo versionable: questo fa sì che il repository tenga traccia della cronologia di un documento e memorizzi le copie di ogni versione del documento." :) –

Problemi correlati