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 SLNSessionGetFileInfo(SLNSessionRef const session, strarg_t const URI, SLNFileInfo *const info) { if(!SLNSessionHasPermission(session, SLN_RDONLY)) return DB_EACCES; if(!URI) return DB_EINVAL; SLNRepoRef const repo = SLNSessionGetRepo(session); DB_env *db = NULL; SLNRepoDBOpen(repo, &db); DB_txn *txn = NULL; int rc = db_txn_begin(db, NULL, DB_RDONLY, &txn); if(rc < 0) { SLNRepoDBClose(repo, &db); return rc; } DB_cursor *cursor; rc = db_txn_cursor(txn, &cursor); assert(!rc); DB_range fileIDs[1]; SLNURIAndFileIDRange1(fileIDs, txn, URI); DB_val URIAndFileID_key[1]; rc = db_cursor_firstr(cursor, fileIDs, URIAndFileID_key, NULL, +1); DB_val file_val[1]; if(rc >= 0) { strarg_t URI2; uint64_t fileID; SLNURIAndFileIDKeyUnpack(URIAndFileID_key, txn, &URI2, &fileID); assert(0 == strcmp(URI, URI2)); if(info) { DB_val fileID_key[1]; SLNFileByIDKeyPack(fileID_key, txn, fileID); rc = db_get(txn, fileID_key, file_val); } } if(rc < 0) { db_txn_abort(txn); txn = NULL; SLNRepoDBClose(repo, &db); return rc; } if(info) { strarg_t const internalHash = db_read_string(file_val, txn); strarg_t const type = db_read_string(file_val, txn); uint64_t const size = db_read_uint64(file_val); info->hash = strdup(internalHash); info->path = SLNRepoCopyInternalPath(repo, internalHash); info->type = strdup(type); info->size = size; if(!info->hash || !info->path || !info->type) { SLNFileInfoCleanup(info); db_txn_abort(txn); txn = NULL; SLNRepoDBClose(repo, &db); return DB_ENOMEM; } } db_txn_abort(txn); txn = NULL; SLNRepoDBClose(repo, &db); return 0; }
int SLNSessionGetValueForField(SLNSessionRef const session, str_t value[], size_t const max, strarg_t const fileURI, strarg_t const field) { if(!SLNSessionHasPermission(session, SLN_RDONLY)) return DB_EACCES; if(!field) return DB_EINVAL; if(max) value[0] = '\0'; int rc = 0; DB_cursor *metafiles = NULL; DB_cursor *values = NULL; SLNRepoRef const repo = SLNSessionGetRepo(session); DB_env *db = NULL; SLNRepoDBOpen(repo, &db); DB_txn *txn = NULL; rc = db_txn_begin(db, NULL, DB_RDONLY, &txn); if(rc < 0) goto done; rc = db_cursor_open(txn, &metafiles); if(rc < 0) goto done; rc = db_cursor_open(txn, &values); if(rc < 0) goto done; DB_range metaFileIDs[1]; SLNTargetURIAndMetaFileIDRange1(metaFileIDs, txn, fileURI); DB_val metaFileID_key[1]; rc = db_cursor_firstr(metafiles, metaFileIDs, metaFileID_key, NULL, +1); if(rc < 0 && DB_NOTFOUND != rc) goto done; for(; rc >= 0; rc = db_cursor_nextr(metafiles, metaFileIDs, metaFileID_key, NULL, +1)) { strarg_t u; uint64_t metaFileID; SLNTargetURIAndMetaFileIDKeyUnpack(metaFileID_key, txn, &u, &metaFileID); assert(0 == strcmp(fileURI, u)); DB_range vrange[1]; SLNMetaFileIDFieldAndValueRange2(vrange, txn, metaFileID, field); DB_val value_val[1]; rc = db_cursor_firstr(values, vrange, value_val, NULL, +1); if(rc < 0 && DB_NOTFOUND != rc) goto done; for(; rc >= 0; rc = db_cursor_nextr(values, vrange, value_val, NULL, +1)) { uint64_t m; strarg_t f, v; SLNMetaFileIDFieldAndValueKeyUnpack(value_val, txn, &m, &f, &v); assert(metaFileID == m); assert(0 == strcmp(field, f)); if(!v) continue; if(0 == strcmp("", v)) continue; size_t const len = strlen(v); memcpy(value, v, MIN(len, max-1)); value[MIN(len, max-1)] = '\0'; goto done; } } done: db_cursor_close(values); values = NULL; db_cursor_close(metafiles); metafiles = NULL; db_txn_abort(txn); txn = NULL; SLNRepoDBClose(repo, &db); return rc; }
ssize_t SLNFilterCopyURIs(SLNFilterRef const filter, SLNSessionRef const session, SLNFilterPosition *const pos, int const dir, bool const meta, str_t *URIs[], size_t const max) { assert(URIs); if(!SLNSessionHasPermission(session, SLN_RDONLY)) return DB_EACCES; if(0 == pos->dir) return DB_EINVAL; if(0 == dir) return DB_EINVAL; if(0 == max) return 0; DB_env *db = NULL; DB_txn *txn = NULL; ssize_t rc = 0; SLNRepoRef const repo = SLNSessionGetRepo(session); SLNRepoDBOpen(repo, &db); rc = db_txn_begin(db, NULL, DB_RDONLY, &txn); if(rc < 0) goto cleanup; rc = SLNFilterPrepare(filter, txn); if(rc < 0) goto cleanup; rc = SLNFilterSeekToPosition(filter, pos, txn); if(rc < 0) goto cleanup; int const stepdir = pos->dir * dir; size_t i = 0; for(; i < max; i++) { size_t const x = stepdir > 0 ? i : max-1-i; rc = SLNFilterGetPosition(filter, pos, txn); if(DB_NOTFOUND == rc) { rc = 0; break; } rc = SLNFilterCopyURI(filter, pos->fileID, meta, txn, &URIs[x]); if(rc < 0) goto cleanup; assert(URIs[x]); SLNFilterStep(filter, pos->dir); } // The results should always be in the first `i` slots, even when // filling them in reverse order. if(stepdir < 0) { memmove(URIs+0, URIs+(max-i), sizeof(*URIs) * i); } assert(rc >= 0); rc = i; cleanup: db_txn_abort(txn); txn = NULL; SLNRepoDBClose(repo, &db); return rc; }
void SLNSessionDBClose(SLNSessionRef const session, DB_env **const dbptr) { assert(session); SLNRepoDBClose(SLNSessionGetRepo(session), dbptr); }