Warning: session_start(): open(/var/lib/php/sessions/sess_v6u3jmnee66tgpc72a49c8lm83, O_RDWR) failed: No space left on device (28) in /var/www/tb-usercake/models/config.php on line 51
Warning: session_start(): Failed to read session data: files (path: /var/lib/php/sessions) in /var/www/tb-usercake/models/config.php on line 51
// A concept should be an object, not just a string.
// Functions that should always be there for child processes:
please include function dbLock.
static interface Derefable {
Concept get();
}
sclass Concept extends DynamicObject {
long id;
//double energy;
//bool defunct;
long created;
// used only internally (cnew)
*(S className) {
super(className);
_created();
}
*() {
className = shortClassName(this);
if (!DynamicObject_loading) {
//print("New concept of type " + className);
_created();
}
}
new L[ refs;
new L][ backRefs;
void _created() {
created = now();
if (!isTrue(_unlisted.get())) register();
}
void put(S field, O value) {
fieldValues.put(field, value);
change();
}
O get(S field) {
ret fieldValues.get(field);
}
class Ref implements Derefable {
A value;
*() {
if (!DynamicObject_loading) refs.add(this);
}
*(A *value) {
refs.add(this);
index();
}
// get owning concept (source)
Concept concept() { ret Concept.this; }
// get target
public A get() { ret value; }
bool has() { ret value != null; }
bool empty() { ret value == null; }
void set(A a) {
if (a == value) ret;
unindex();
value = a;
index();
}
void set(Ref ref) { set(ref.get()); }
void clear() { set((A) null); }
void index() {
if (value != null)
value.backRefs.add(this);
change();
}
void unindex() {
if (value != null)
value.backRefs.remove(this);
}
public S toString() {
ret str(get());
}
}
class RefL extends AbstractList {
new L][> l;
public A set(int i, A o) {
A prev = l.get(i).get();
l.get(i).set(o);
change();
ret prev;
}
public void add(int i, A o) {
l.add(i, new Ref(o));
change();
}
public A get(int i) {
ret l.get(i).get();
}
public A remove(int i) {
A a = l.remove(i).get();
change();
ret a;
}
public int size() {
ret l.size();
}
// derefs
void addAll_(L l) {
for (O x : l) add_(x);
}
// derefs
void add_(O o) {
add((A) deref(o));
}
}
void delete() {
if (id == 0) ret;
concepts.remove(id);
conceptsByClass.get(getClass()).remove(id);
id = 0;
//name = "[defunct " + name + "]";
//defunct = true;
//energy = 0;
for (Ref r : refs)
r.unindex();
refs.clear();
change();
}
// register a previously unlisted concept
void register() {
if (id != 0) ret; // already registered
id = newID();
concepts.put(id, this);
_addToClassMap();
change();
}
void _addToClassMap() {
Class c = getClass();
Map map = conceptsByClass.get(c);
if (map == null) {
// we're the first object, register this class
Class superclass = c.getSuperclass();
if (superclass != Concept)
subclasses.put(superclass, c);
conceptsByClass.put(c, map = new TreeMap);
}
map.put(id, this);
}
} // class Concept
// for inter-process communication
// prepared for string ids if we do them later
sclass PassRef {
S id;
*() {} // make serialisation happy
*(long id) { this.id = str(id); }
*(Concept c) { this(c.id); }
long longID() { ret parseLong(id); }
public S toString() {
ret id;
}
}
sclass Event extends Concept {}
// This can be set by client
static bool concepts_quietSave;
static Map concepts = synchroTreeMap();
static Map> conceptsByClass = synchroHashMap();
static new MultiMap subclasses;
static long idCounter;
static volatile long changes = 1, changesWritten;
static volatile java.util.Timer autoSaver;
static volatile bool savingConcepts;
static new ThreadLocal _unlisted;
static bool concepts_saveOneMore;
static S conceptsLoadedFrom;
static int concepts_internStringsLongerThan = 10;
static int concepts_autoSaveInterval = 1000;
static long newID() {
do {
++idCounter;
} while (hasConcept(idCounter));
ret idCounter;
}
ssvoid loadConceptsFrom(S programID) {
conceptsLoadedFrom = programID;
clearConcepts();
DynamicObject_loading = true;
try {
structure_internStringsLongerThan = concepts_internStringsLongerThan;
readLocally(programID, "concepts");
readLocally(programID, "idCounter");
assignConceptsToUs();
} finally {
DynamicObject_loading = false;
}
}
svoid assignConceptsToUs() {
for (Concept c : values(concepts)) {
c._addToClassMap();
callOpt(c, "_doneLoading2");
}
}
ssvoid loadConcepts() {
loadConceptsFrom(programID());
}
static Concept getConcept(S id) {
ret empty(id) ? null : getConcept(parseLong(id));
}
static Concept getConcept(long id) {
ret (Concept) concepts.get((long) id);
}
static Concept getConcept(PassRef ref) {
ret ref == null ? null : getConcept(ref.longID());
}
static bool hasConcept(long id) {
ret concepts.containsKey((long) id);
}
static bool hasConcept(Class c, O... params) {
ret conceptWhere(c, params) != null;
}
static Concept deleteConcept(long id) {
Concept c = getConcept(id);
if (c == null)
print("Concept " + id + " not found");
else
c.delete();
ret c;
}
// call in only one thread
static void saveConceptsIfDirty() {
saveConceptsIfDirty(programID());
}
static void saveConceptsIfDirty(S programID) {
savingConcepts = true;
try {
S s;
synchronized(main.class) {
bool change = changes != changesWritten;
if (!change && !concepts_saveOneMore) ret;
changesWritten = changes;
concepts_saveOneMore = change;
save(programID, "idCounter");
s = structure(cloneMap(concepts));
}
if (!concepts_quietSave)
print("Saving " + l(s) + " chars (" + changesWritten + ")");
saveTextFile(getProgramFile(programID, "concepts.structure"), s);
copyFile(getProgramFile(programID, "concepts.structure"), getProgramFile(programID, "concepts.structure.backup" + ymd() + "-" + formatInt(hours(), 2)));
} finally {
savingConcepts = false;
}
}
static void saveConcepts() {
saveConceptsIfDirty();
}
static void saveConceptsTo(S programID) {
saveConceptsIfDirty(programID);
}
static void clearConcepts() {
concepts.clear();
conceptsByClass.clear();
subclasses.clear();
change();
}
static synchronized void change() {
++changes;
}
// auto-save every second if dirty
static synchronized void autoSaveConcepts() {
if (autoSaver == null)
autoSaver = doEvery(concepts_autoSaveInterval, r { saveConcepts(); });
}
static void cleanMeUp() {
if (autoSaver != null) {
autoSaver.cancel();
autoSaver = null;
}
while (savingConcepts) sleep(10);
saveConceptsIfDirty();
}
static Map getIDsAndNames() {
new Map map;
Map cloned = cloneMap(concepts);
for (long id : keys(cloned))
map.put(id, cloned.get(id).className);
ret map;
}
static A findBackRef(Concept c, Class type) {
ret findBackRefOfType(c, type);
}
static A findBackRefOfType(Concept c, Class type) {
for (Concept.Ref r : c.backRefs)
if (instanceOf(r.concept(), type))
ret (A) r.concept();
null;
}
static L findBackRefs(Concept c, Class type) {
new L l;
for (Concept.Ref r : c.backRefs)
if (instanceOf(r.concept(), type))
l.add((A) r.concept());
ret l;
}
static A conceptOfType(Class type) {
ret firstOfType(allConcepts(), type);
}
static L conceptsOfType(Class type) {
//ret filterByType(allConcepts(), type);
new L l;
_collectInstances(type, l);
ret l;
}
svoid _collectInstances(Class c, L l) {
l.addAll(values(conceptsByClass.get(c)));
for (Class sub : subclasses.get(c))
_collectInstances(sub, l);
}
static L listConcepts(Class type) {
ret conceptsOfType(type);
}
static L list(S type, O... params) {
ret empty(params) ? conceptsOfType(type)
: conceptsWhere(type, params);
}
static L list(Class type, O... params) {
ret empty(params) ? conceptsOfType(type)
: conceptsWhere(type, params);
}
static L conceptsOfType(S type) {
ret filterByDynamicType(allConcepts(), "main$" + type);
}
static bool hasConceptOfType(Class extends Concept> type) {
ret hasType(allConcepts(), type);
}
static void persistConcepts() {
concepts_quietSave = true;
loadConcepts();
autoSaveConcepts();
}
static void loadAndAutoSaveConcepts() {
persistConcepts();
}
// We love synonyms
static void conceptPersistence() {
persistConcepts();
}
// Runs r if there is no concept of that type
static A ensureHas(Class c, Runnable r) {
A a = conceptOfType(c);
if (a == null) {
r.run();
a = conceptOfType(c);
if (a == null)
fail("Concept not made by " + r + ": " + shortClassName(c));
}
ret a;
}
// Ensures that every concept of type c1 is ref'd by a concept of
// type c2.
// Type of func: voidfunc(concept)
static void ensureHas(Class extends Concept> c1, Class extends Concept> c2, O func) {
for (Concept a : conceptsOfType(c1)) {
Concept b = findBackRef(a, c2);
if (b == null) {
callF(func, a);
b = findBackRef(a, c2);
if (b == null)
fail("Concept not made by " + func + ": " + shortClassName(c2));
}
}
}
// Type of func: voidfunc(concept)
static void forEvery(Class extends Concept> type, O func) {
for (Concept c : conceptsOfType(type))
callF(func, c);
}
static int deleteAll(Class extends Concept> type) {
L l = (L) conceptsOfType(type);
for (Concept c : l) c.delete();
ret l(l);
}
static Collection allConcepts() {
synchronized(concepts) {
ret new L(values(concepts));
}
}
static Concept cnew(S name, O... values) {
Class extends Concept> cc = findClass(name);
Concept c = cc != null ? nuObject(cc) : new Concept(name);
csetAll(c, values);
ret c;
}
static A cnew(Class cc, O... values) {
A c = nuObject(cc);
csetAll(c, values);
ret c;
}
static void csetAll(Concept c, O... values) {
cset(c, values);
}
static void cset(Concept c, O... values) ctex {
values = expandParams(c.getClass(), values);
warnIfOddCount(values);
for (int i = 0; i+1 < l(values); i += 2) {
S field = (S) values[i];
O value = values[i+1];
Field f = setOpt_findField(c.getClass(), field);
//print("cset: " + c.id + " " + field + " " + struct(value) + " " + f);
if (value instanceof PassRef) value = getConcept((PassRef) value);
value = deref(value);
if (value instanceof S && l((S) value) >= concepts_internStringsLongerThan) value = ((S) value).intern();
if (f == null)
c.fieldValues.put(field, value instanceof Concept ? c.new Ref((Concept) value) : value);
else if (isSubtypeOf(f.getType(), Concept.Ref.class))
((Concept.Ref) f.get(c)).set((Concept) value);
else
f.set(c, value);
}
change();
}
static O cget(Concept c, S field) {
O o = getOptDyn(c, field);
if (o instanceof Concept.Ref) ret ((Concept.Ref) o).get();
ret o;
}
static PassRef toPassRef(Concept c) {
ret new PassRef(c);
}
// inter-process methods
static PassRef xnew(S name, O... values) {
ret new PassRef(cnew(name, values));
}
static void xset(long id, S field, O value) {
xset(new PassRef(id), field, value);
}
static void xset(PassRef c, S field, O value) {
if (value instanceof PassRef)
value = getConcept((PassRef) value);
cset(getConcept(c), field, value);
}
// get class name of concept
static O xclass(PassRef id) {
Concept c = getConcept(id);
ret c == null ? null : c.className;
}
static O xget(long id, S field) {
ret xget(new PassRef(id), field);
}
static O xget(PassRef c, S field) {
ret export(cget(getConcept(c), field));
}
static void xdelete(long id) {
xdelete(new PassRef(id));
}
static void xdelete(PassRef c) {
getConcept(c).delete();
}
static L xlist() {
ret map("toPassRef", allConcepts());
}
static L xlist(S className) {
ret map("toPassRef", conceptsOfType(className));
}
// end of IPC methods
// make concept instance that is not connected to DB
static A unlisted(Class c) {
_unlisted.set(true);
try {
ret nuObject(c);
} finally {
_unlisted.set(null);
}
}
static A unary(Class c) {
A a = conceptOfType(c);
if (a == null)
a = nuObject(c);
ret a;
}
static Android3 makeDBBot(S name) {
ret makeBot(name, makeDBResponder());
}
static L] exposedDBMethods = ll("xlist", "xnew", "xset", "xdelete", "xget", "xclass");
static O makeDBResponder() {
ret new O {
S answer(S s) {
ret exposeMethods(s, exposedDBMethods);
}
};
}
static O export(O o) {
if (o instanceof Concept)
ret new PassRef(((Concept) o).id);
ret o;
}
ssvoid saveConceptsBack() {
saveConceptsTo(assertNotNull(conceptsLoadedFrom));
}
static bool eq(O a, O b) {
ret _eq(deref(a), deref(b));
}