Prevalência com Swap e/ou Passivation

Andei pensando nisso ontem…

C já brincou com RMI?? Quando vc tem um objeto remoto, vc tem na verdade um proxy. O proxy sabe:

  1. Transformar uma chamada de método em um comando seriado que ele envia por um socket
  2. Abrir conexão com a máquina de destino.

Minha idéia começou com o problema da deleção: se vc deleta um objeto do sistema prevalente, o que vc faz com as referências?

Um ponto de partida é vc “saber” quando um objeto é uma entidade (se o nome é muito relacional pra vc, use “remoto”) ou não. Quando um obj é entidade, a associação (isto é, as referências) pra ele precisam ser mais espertas que uma ref. java.

Então que tal implementar uma classe que lida com essa ref esperta? Ela pode implementar Observer e se “desconectar” quando um objeto é removido do seu mapa (pra resolver o problema 1). E toda vez que vc dá get(), o que ela faz é ir pro mapa e dar get() pra pegar o objeto.

Um User tem uma ref esperta pra um Account, então o getAccount() do User tb vai, eventualmente, pro mapa.

Vc ainda tem que lidar com os pobres OIDs, mas isso não é tão ruim. O importante é que durante o design, o programador saiba quais classes têm instâncias que vale a pena passivar.

Pode até ser um esqueminha IoC baseado em interfaces (p.e. implements Passivatable). De qq jeito, como vc precisa de proxies, vc acaba precisando de factories. Mas com um pouco de esforço (e CGLIB), dá pra fazer um esquema 100% dinâmico.

bom, se eu tiver tempo, vou ver esse esquema da ref esperta, posto aqui qq coisa que eu encontre. Tô empolgado! : )

[]s

[quote=“dukejeffrie”]Andei pensando nisso ontem…

C já brincou com RMI?? Quando vc tem um objeto remoto, vc tem na verdade um proxy. O proxy sabe:

  1. Transformar uma chamada de método em um comando seriado que ele envia por um socket
  2. Abrir conexão com a máquina de destino.

Minha idéia começou com o problema da deleção: se vc deleta um objeto do sistema prevalente, o que vc faz com as referências?

Um ponto de partida é vc “saber” quando um objeto é uma entidade (se o nome é muito relacional pra vc, use “remoto”) ou não. Quando um obj é entidade, a associação (isto é, as referências) pra ele precisam ser mais espertas que uma ref. java.

Então que tal implementar uma classe que lida com essa ref esperta? Ela pode implementar Observer e se “desconectar” quando um objeto é removido do seu mapa (pra resolver o problema 1). E toda vez que vc dá get(), o que ela faz é ir pro mapa e dar get() pra pegar o objeto.

Um User tem uma ref esperta pra um Account, então o getAccount() do User tb vai, eventualmente, pro mapa.

Vc ainda tem que lidar com os pobres OIDs, mas isso não é tão ruim. O importante é que durante o design, o programador saiba quais classes têm instâncias que vale a pena passivar.

Pode até ser um esqueminha IoC baseado em interfaces (p.e. implements Passivatable). De qq jeito, como vc precisa de proxies, vc acaba precisando de factories. Mas com um pouco de esforço (e CGLIB), dá pra fazer um esquema 100% dinâmico.

bom, se eu tiver tempo, vou ver esse esquema da ref esperta, posto aqui qq coisa que eu encontre. Tô empolgado! : )

[]s[/quote]

Acho que a solução é usar proxies mesmo, como o CV falou desde o início. Inclusive na documentação de Soft References está escrito:

O único porém é que vc terá que escrever uma interface para todo objeto que vc queira passivar. Como RMI e EJB.

Então se eu tenho um objeto User, vou ter que fazer:

public interface User {
  public int getId();
  public String getName();
  public Account getAccount();
}

public class UserImpl implements User {
  // a implementacao do objeto em si...
}

public class UserHandler implements InvocationHandler {
// a mágica da soft reference acontece aqui...
// se está passivado ativa aqui !!!!
}

e colocar um método estático getInstance no UserImpl que retorne o proxy:


User u = (User) Proxy.newProxyInstance(User.class.getClassLoader(),

                                  new Class[] {User.class},

                                  new UserHandler(new UserImpl()));
}

O nosso sistema de prevalencia está ficando com cara de EJB, mas se não há outro jeito, fazer o que? Isso tem que ser muito bem explicadinho para o programador, se nao o cara vai debandar. :slight_smile:

Depois tem que ver se dá para serializar direitinho esse proxy no snapshot.

:cry:

[quote=“saoj”]Acho que a solução é usar proxies mesmo, como o CV falou desde o início.
(…)
Depois tem que ver se dá para serializar direitinho esse proxy no snapshot.
[/quote]

Nunca me passou pela cabeça fazer isso sem proxies. O lance é que se o proxy conhece o mapa (i.e. tem uma referencia forte para ele), ele deve ser transiente. Se ele tem que ser transiente, eu preciso encontrar um jeito de conectar de novo o proxy ao mapa. Isto é, eu preciso de uma Facade que saiba me entregar o mapa (Pode ser um “Not a Container”)

Como na API de logging, onde eu faço Logger.getLogger(), posso fazer um método getMap() que chame PassiveMap.getInstance()… daí fica:

// construtor
public SmartReference(Class targetClass) {
   this.targetClass = obj.getClass();
   this.id = null;
}

protected PassiveMap getMap() {
   return PassiveMap.getInstance(targetClass);
}

public PassiveObject get() {
   return getMap().get(this.id);
}

public void set(PassiveObject obj) {
   if (!this.targetClass.isInstance(obj)) {
      throw ClassCastException(...);
   }
   getMap().put(obj.getId(), obj);
}

// no cliente
public class User {
  private SmartReference account;

   public void setAccount(Account c) {
      account.set(c);
   }

   public Account getAccount() {
      return (Account) account.get();
   }
}

Numa futura implementação, dá pra usar CGLIB pra “aspectar” um objeto de forma que ele use uma SmartReference toda vez que ele tiver como membro uma ref a um objeto que implemente PassiveObject.

[quote=“saoj”]O nosso sistema de prevalencia está ficando com cara de EJB, mas se não há outro jeito, fazer o que? Isso tem que ser muito bem explicadinho para o programador, se nao o cara vai debandar. :slight_smile:
[/quote]

Eu ainda digo que devia ser separado… 8)

[]s!

Vc está falando de java.lang.reflect.Proxy ???

Se estiver vc vai ter que implementar aquele esquema que eu falei acima, isto é, para cada objeto que vc queira passivar vc vai ter que implementar duas interfaces pra ele (User e UserHandler). Não dá para fugir disso.

Mas acho que entendi o que vc quer fazer :slight_smile:

Ao invés de java.lang.reflect.Proxy, vc quer criar um objeto que vai guardar a referencia de uma forma esperta, o tal do SmartReference.

Pô, acho que vc mantou a charada !!! :shocked!:

Algo assim:

public class SmartReference implements Serializable {
    
    private transient PassivationMap map = null;
    private Integer oid = null;
    
    public SmartReference(Map map, Object obj) {
        this.map = map;
        this.oid = new Integer(obj.hasCode());
        set(obj);
    }
    
    public Object get() {
        return map.get(oid);
    }
    
    public void set(Object obj) {
        map.put(oid, obj);
    }
    
    // use isso daqui para iniciar objetos transientes !!!
    // Isso é um hack legal que a Sun fez !!! hehehe
    private void readObject(ObjectInputStream stream)  throws ClassNotFoundException, IOException {
        stream.defaultReadObject();
        // map = .....
        // temos que dar um jeito de voltar com o PassivationMap aqui...
        // deve ter um jeito tranquilo...
    }


    
}

Dessa maneira o proxy (SmartReference) não precisa ter uma referencia forte para o Objeto. O PassivationMap saberá se livrar da referencia quando ele passivar o objeto. (Estou abstraindo o PassivationMap, pois já implementei ele!)

A única exigência é que o Objeto produza um hashCode único, ou seja, o objeto precisa ter um identificar único, como uma chave primária.

Será que matamos o problema ??? O que falta ???

Implementei um suporte mínimo de passivação no Space4J. Basicamente criei um PassivationMap e um PassivationObj. Tudo que o programador precisa fazer é colocar os seus objetos num PassivationMap que o sistema cuida da passivação pra ele.

PassivationMap: Recebe Object via put e devolve PassivationObj via get. Monitora os PassivationObjs para passivação. Se um PassivationObj não é acessado a mais de N minutos, a PassivationMap passiva ele.

PassivationObj: Protege a referencia do objeto sujeito a passivação, como o SmartReference acima. Possui um timestamp (lastAccessTime) e um filename onde o objeto deverá ser serializado. Expõe o objeto ao mundo via o método get(), que se necessário recupera o objeto do disco.

Notas:

  1. Todo objeto sujeito a passivação precisa ter um oid, que deverá ser retornado pela sua função hashCode e será usado na construção do filename. Normalmente esse oid será o id único da entidade.

  2. Nenhum objeto deve manter referências fortes a um objeto sujeito a passivação, mas sim ao seu PassivationObj, que nada mais é que um Wrapper do objeto.

  3. Não usei SoftReference para ter mais controle sobre as circunstâncias da passivação. Além disso como uma soft reference notifica o mundo exterior que está coletando o objeto da sua referencia ??? Acho que só via o finalize do Objeto, mas aí teríamos que fazer um callback do Objecto para o seu PassivationObj via uma interface. Precisamos ser informados disso para serializar o objeto nesse momento. Deixando o PassivationMap controlar tudo isso fica mais fácil.

O código está em http://space4j.dev.java.net/. Aguardo sugestões, críticas, etc.

[]'s

Sergio

Uhuuuuu!!!

Passivation rulis!!

nunca mais bd!

legal, saoj, vou dar uma olhada assim que der pra respirar aqui!!

Tô curioso pra saber como vc carrega o passivation map…

[]s!!