public static Freezable newFreezable(int id) { Freezable f = GOLD[id]; if (f == null) { try { GOLD[id] = f = (Freezable) Class.forName(TypeMapGen.CLAZZES[id]).newInstance(); } catch (Exception e) { throw Log.errRTExcept(e); } } return f.newInstance(); }
/** * Checks that this Freezable object can be mutated from the given {@link Environment}. * * @param object a Freezable object that we check is still mutable. * @param env the {@link Environment} attempting the mutation. * @throws MutabilityException when the object was frozen already, or is from another context. */ public static void checkMutable(Freezable object, Environment env) throws MutabilityException { if (!object.mutability().isMutable()) { throw new MutabilityException("trying to mutate a frozen object"); } // Consider an {@link Environment} e1, in which is created {@link UserDefinedFunction} f1, // that closes over some variable v1 bound to list l1. If somehow, via the magic of callbacks, // f1 or l1 is passed as argument to some function f2 evaluated in {@link environment} e2 // while e1 is be mutable, e2, being a different {@link Environment}, should not be // allowed to mutate objects from e1. It's a bug, that shouldn't happen in our current code // base, so we throw an AssertionError. If in the future such situations are allowed to happen, // then we should throw a MutabilityException instead. if (!object.mutability().equals(env.mutability())) { throw new AssertionError("trying to mutate an object from a different context"); } }
public static void main(String[] args) { // Shared freezable object final F<ObjectInterface> freezableObj = Freezable.of(new MyObject(0)); System.out.println("We create a shared object: " + freezableObj); // Create refs to freezableObj R<ObjectInterface> r1 = R.createRef(freezableObj); R<ObjectInterface> r2 = R.createRef(freezableObj); System.out.println("Initial configuration"); System.out.println("R1 " + r1); System.out.println("R2 " + r2); // One of them changes the value System.out.println("R2 changes the value of the instance to 5"); r2.instance().setValue(5); // Now, we freeze ref2. Ref2 will keep the original reference. r1.freeze(); System.out.println("R1 calls freeze()"); System.out.println("R1 " + r1); System.out.println("R2 " + r2); // Ref1 changes the content. Since Ref2 has frozen the instance, Ref1 obtains a copy. // r1.get().instance() returns a proxied interface of the object. Method setValue // is intercepted. Since freezableObj is frozen, a new copy is generated and assigned // to r1. System.out.println("R2 modify the value to 1 and obtains a new copy"); r2.instance().setValue(1); // Now r2 has a different copy System.out.println("R1 " + r1); System.out.println("R2 " + r2); System.out.println("We create R3 with the first instance (still locked)"); R<ObjectInterface> r3 = new R<>(freezableObj); System.out.println("R3 " + r3); System.out.println("R2 has freedom to change its own copy"); r2.instance().setValue(100); System.out.println("R1 " + r1); System.out.println("R2 " + r2); System.out.println("R3 " + r3); System.out.println("R3 changes its copy"); r3.instance().setValue(200); System.out.println("R1 " + r1); System.out.println("R2 " + r2); System.out.println("R3 " + r3); }
// Also, allow auto-serialization public static void put(Key key, Freezable fr) { if (fr == null) UKV.put(key, null); else UKV.put(key, new Value(key, fr.write(new AutoBuffer()).buf())); }