use of org.nustaq.kontraktor.IPromise in project kontraktor by RuedigerMoeller.
the class EmbeddedRealLive method createTable.
/**
* WARNING: never create more than one table using the same file. This will
* result in corrupted data for sure. As actor refs (tables) are thread save,
* just init a singleton containing all your tables once.
*
* @param desc
* @param dataDir - if null use path from description
* @return a thread save actor reference to a newly loaded or created table
*/
public IPromise<RealLiveTable> createTable(TableDescription desc, String dataDir) {
RealLiveTableActor table = Actors.AsActor(RealLiveTableActor.class);
Supplier<RecordStorage> memFactory;
if (desc.getFilePath() == null) {
Log.Info(this, "no file specified. all data in memory " + desc.getName());
switch(desc.getStorageType()) {
case CACHED:
memFactory = () -> new CachedOffHeapStorage(new OffHeapRecordStorage(desc.getKeyLen(), desc.getSizeMB(), desc.getNumEntries()), new HeapRecordStorage());
break;
default:
Log.Error(this, "unknown storage type " + desc.getStorageType() + " default to PERSIST");
case PERSIST:
memFactory = () -> new OffHeapRecordStorage(desc.getKeyLen(), desc.getSizeMB(), desc.getNumEntries());
break;
case TEMP:
memFactory = () -> new HeapRecordStorage();
break;
}
} else {
String bp = dataDir == null ? desc.getFilePath() : dataDir;
desc.filePath(bp);
new File(bp).mkdirs();
String file = bp + "/" + desc.getName() + "_" + desc.getShardNo() + ".bin";
switch(desc.getStorageType()) {
case CACHED:
Log.Info(this, "memory mapping file " + file);
memFactory = () -> new CachedOffHeapStorage(new OffHeapRecordStorage(file, desc.getKeyLen(), desc.getSizeMB(), desc.getNumEntries()), new HeapRecordStorage());
break;
default:
Log.Error(this, "unknown storage type " + desc.getStorageType() + " default to PERSIST");
case PERSIST:
Log.Info(this, "memory mapping file " + file);
memFactory = () -> new OffHeapRecordStorage(file, desc.getKeyLen(), desc.getSizeMB(), desc.getNumEntries());
break;
case TEMP:
memFactory = () -> new HeapRecordStorage();
break;
}
}
table.init(memFactory, desc).await(30_000);
return new Promise(table);
}
use of org.nustaq.kontraktor.IPromise in project kontraktor by RuedigerMoeller.
the class StorageDriver method atomicQuery.
/**
* apply the function to the record with given key and return the result inside a promise
*
* changes to the record inside the function are applied to the real record and a change message
* is generated.
*
* In case the function returns a changemessage (add,putRecord,remove ..), the change message is applied
* to the original record and the change is broadcasted
*
* @param key
* @param action
* @return the result of function.
*/
public IPromise atomicQuery(String key, RLFunction<Record, Object> action) {
Record rec = getStore().get(key);
if (rec == null) {
final Object apply = action.apply(rec);
if (apply instanceof ChangeMessage) {
receive((ChangeMessage) apply);
}
return new Promise(apply);
} else {
PatchingRecord pr = new PatchingRecord(rec);
final Object res = action.apply(pr);
if (res instanceof ChangeMessage) {
receive((ChangeMessage) res);
} else {
UpdateMessage updates = pr.getUpdates();
if (updates != null) {
receive(updates);
}
}
return new Promise(res);
}
}
use of org.nustaq.kontraktor.IPromise in project kontraktor by RuedigerMoeller.
the class ServiceActor method awaitRequiredServices.
public IPromise awaitRequiredServices() {
Log.Info(this, "connecting required services ..");
if (requiredServices.size() == 0) {
return resolve();
}
IPromise res = new Promise<>();
gravity.getServiceMap().then((smap, err) -> {
List<IPromise<Object>> servicePromis = new ArrayList();
String[] servNames = getAllServiceNames();
for (int i = 0; i < servNames.length; i++) {
String servName = servNames[i];
ServiceDescription serviceDescription = smap.get(servName);
if (serviceDescription != null && requiredServices.get(servName) instanceof Actor == false) {
if (serviceDescription.getConnectable() == null) {
Log.Error(this, "No connecteable defined for service " + serviceDescription.getName());
}
IPromise connect;
try {
Log.Info(this, "connect " + serviceDescription.getConnectable());
connect = serviceDescription.getConnectable().connect();
} catch (Throwable th) {
Log.Error(this, th, "failed to connect " + serviceDescription.getName());
continue;
}
Promise notify = new Promise();
servicePromis.add(notify);
connect.then((actor, connectionError) -> {
if (actor != null) {
requiredServices.put(servName, actor);
notify.complete();
} else {
requiredServices.put(servName, UNCONNECTED);
Log.Warn(this, "failed to connect " + servName + " " + connectionError + " " + serviceDescription.getConnectable());
notify.reject("failed to connect " + servName + " " + connectionError);
}
});
} else {
res.reject("required service " + servName + " not registered.");
return;
}
}
if (!res.isSettled()) {
all(servicePromis).timeoutIn(15000).then(res).onTimeout(() -> {
// todo:retry
Log.Info(this, "failed to connect required services, retry");
});
}
});
return res;
}
use of org.nustaq.kontraktor.IPromise in project kontraktor by RuedigerMoeller.
the class DataClient method export.
/**
* @param directory
*/
public IPromise export(String directory) {
Promise res = new Promise();
// use separate thread to enable slowly, blocking processing
Actors.exec.execute(() -> {
File d = new File(directory);
if (d.exists() && (!d.isDirectory() || !d.canWrite())) {
res.reject(new RuntimeException("cannot write to " + d + " or not a directory"));
return;
} else {
d.mkdirs();
}
FSTConfiguration writeConf = FSTConfiguration.createDefaultConfiguration();
Arrays.stream(config.getSchema()).forEach(desc -> {
try {
DataOutputStream fout = new DataOutputStream(new FileOutputStream(new File(d, desc.getName() + ".oos")));
CountDownLatch pl = new CountDownLatch(shards.length);
for (int i = 0; i < shards.length; i++) {
TableSpaceActor shard = shards[i];
Log.Info(this, "exporting shard " + i + " table " + desc.getName());
try {
RealLiveTable table = shard.getTableAsync(desc.getName()).await(60_000);
table.forEach(rec -> true, (rec, err) -> {
if (rec != null) {
try {
// write marker to enable recovery in case of corruption
synchronized (fout) {
fout.write(31);
fout.write(32);
fout.write(33);
fout.write(34);
byte[] b = writeConf.asByteArray(rec);
fout.writeInt(b.length);
fout.write(b);
}
} catch (IOException e) {
Log.Error(this, e);
}
} else if (err != null) {
Log.Warn(this, "error during export " + err);
pl.countDown();
} else {
// fin
pl.countDown();
}
});
} catch (Exception e) {
Log.Error(this, "export failure " + desc.getName() + " shard " + i);
}
}
try {
boolean succ = pl.await(5, TimeUnit.MINUTES);
if (!succ)
Log.Error(this, "export timed out on table " + desc.getName());
try {
fout.close();
} catch (IOException e) {
Log.Error(this, e);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
} catch (FileNotFoundException e) {
Log.Error(this, e);
}
});
res.complete();
});
return res;
}
use of org.nustaq.kontraktor.IPromise in project kontraktor by RuedigerMoeller.
the class DataClient method connect.
public IPromise connect(DataCfg config, TableSpaceActor[] shards, ServiceActor hostingService) {
this.config = config;
this.hostingService = hostingService;
this.shards = shards;
syncTableAccess = new HashMap();
tableSharding = new TableSpaceSharding(shards, key -> Math.abs(key.hashCode()) % shards.length);
tableSharding.init().await();
TableDescription[] schema = config.getSchema();
return all(schema.length, i -> {
Promise p = new Promise();
tableSharding.createOrLoadTable(schema[i]).then((r, e) -> {
if (r != null) {
syncTableAccess.put(schema[i].getName(), r);
}
p.complete(r, e);
});
return p;
});
}
Aggregations