int SLNSubmissionStoreBatch(SLNSubmissionRef const *const list, size_t const count) { if(!count) return 0; // Session permissions were already checked when the sub was created. SLNRepoRef const repo = SLNSessionGetRepo(list[0]->session); DB_env *db = NULL; SLNRepoDBOpen(repo, &db); DB_txn *txn = NULL; int rc = db_txn_begin(db, NULL, DB_RDWR, &txn); if(rc < 0) { SLNRepoDBClose(repo, &db); return rc; } uint64_t sortID = 0; rc = DB_NOTFOUND; for(size_t i = 0; i < count; i++) { if(!list[i]) continue; assert(repo == SLNSessionGetRepo(list[i]->session)); rc = SLNSubmissionStore(list[i], txn); if(rc < 0) break; uint64_t const metaFileID = list[i]->metaFileID; if(metaFileID > sortID) sortID = metaFileID; } if(rc >= 0) { rc = db_txn_commit(txn); txn = NULL; } else { db_txn_abort(txn); txn = NULL; } SLNRepoDBClose(repo, &db); if(rc >= 0) SLNRepoSubmissionEmit(repo, sortID); return rc; }
int SLNSessionCreateSession(SLNSessionRef const session, SLNSessionRef *const out) { assert(out); if(!session) return DB_EACCES; SLNSessionCacheRef const cache = session->cache; uint64_t const userID = session->userID; SLNMode const mode = session->mode; strarg_t const username = session->username; DB_env *db = NULL; DB_txn *txn = NULL; SLNSessionRef alt = NULL; byte_t key_raw[SESSION_KEY_LEN]; int rc = async_random(key_raw, sizeof(key_raw)); if(rc < 0) goto cleanup; byte_t key_enc[SHA256_DIGEST_LENGTH]; SHA256(key_raw, sizeof(key_raw), key_enc); str_t key_str[SESSION_KEY_HEX+1]; tohex(key_str, key_enc, SESSION_KEY_LEN); key_str[SESSION_KEY_HEX] = '\0'; rc = SLNSessionDBOpen(session, SLN_RDWR, &db); // TODO: Custom permission? if(rc < 0) goto cleanup; rc = db_txn_begin(db, NULL, DB_RDWR, &txn); if(rc < 0) goto cleanup; uint64_t const sessionID = db_next_id(SLNSessionByID, txn); DB_val key[1], val[1]; SLNSessionByIDKeyPack(key, txn, sessionID); SLNSessionByIDValPack(val, txn, userID, key_str); rc = db_put(txn, key, val, DB_NOOVERWRITE_FAST); if(rc < 0) goto cleanup; rc = db_txn_commit(txn); txn = NULL; SLNSessionDBClose(session, &db); if(rc < 0) goto cleanup; rc = SLNSessionCreateInternal(cache, sessionID, key_raw, key_enc, userID, mode, username, &alt); if(rc < 0) goto cleanup; *out = alt; alt = NULL; cleanup: db_txn_abort(txn); txn = NULL; SLNSessionDBClose(session, &db); SLNSessionRelease(&alt); return rc; }
int SLNSessionAddMetaMap(SLNSessionRef const session, strarg_t const metaURI, strarg_t const targetURI) { uint64_t const sessionID = SLNSessionGetID(session); DB_env *db = NULL; DB_txn *txn = NULL; int rc = SLNSessionDBOpen(session, SLN_RDWR, &db); if(rc < 0) goto cleanup; rc = db_txn_begin(db, NULL, DB_RDWR, &txn); if(rc < 0) goto cleanup; uint64_t nextID = SLNNextMetaMapID(txn, sessionID); if(!nextID) rc = DB_EIO; if(rc < 0) goto cleanup; DB_val mainkey[1], mainval[1]; SLNSessionIDAndMetaMapIDToMetaURIAndTargetURIKeyPack(mainkey, txn, sessionID, nextID); SLNSessionIDAndMetaMapIDToMetaURIAndTargetURIValPack(mainval, txn, metaURI, targetURI); rc = db_put(txn, mainkey, mainval, DB_NOOVERWRITE_FAST); if(rc < 0) goto cleanup; DB_val fwdkey[1], fwdval[1]; SLNMetaURIAndSessionIDToMetaMapIDKeyPack(fwdkey, txn, metaURI, sessionID); SLNMetaURIAndSessionIDToMetaMapIDValPack(fwdval, txn, nextID); rc = db_put(txn, fwdkey, fwdval, DB_NOOVERWRITE_FAST); if(rc < 0) goto cleanup; DB_val revkey[1], revval[1]; SLNTargetURISessionIDAndMetaMapIDKeyPack(revkey, txn, targetURI, sessionID, nextID); db_nullval(revval); rc = db_put(txn, revkey, revval, DB_NOOVERWRITE_FAST); if(rc < 0) goto cleanup; rc = db_txn_commit(txn); txn = NULL; cleanup: db_txn_abort(txn); txn = NULL; SLNSessionDBClose(session, &db); return rc; }
static int db_work(EFSSyncRef const sync, struct queues *const cur) { EFSRepoRef const repo = EFSSessionGetRepo(sync->session); DB_env *db; EFSRepoDBOpen(repo, &db); DB_txn *txn; rc = db_txn_begin(db, NULL, DB_RDWR, &txn); if(DB_SUCCESS != rc) { EFSRepoDBClose(repo, &db); return rc; } // TODO: Process queues in cur. // TODO: Submissions should go to an EFSWriter that does its own batching // But two layers of batching is a bad idea... // Instead of using EFSWriter, do custom inter-sync batching without additional latency rc = db_txn_commit(txn); txn = NULL; EFSRepoDBClose(repo, &db); if(DB_SUCCESS != rc) return rc; return DB_SUCCESS; }