int si_recover(si *i) { sr *r = i->r; int exist = ss_vfsexists(r->vfs, i->scheme->path); if (exist == 0) goto deploy; if (i->scheme->path_fail_on_exists) { sr_error(r->e, "directory '%s' already exists", i->scheme->path); return -1; } int rc = si_recoverdrop(i, r); switch (rc) { case -1: return -1; case 1: goto deploy; } rc = si_schemerecover(i->scheme, r); if (ssunlikely(rc == -1)) return -1; r->scheme = &i->scheme->scheme; r->fmt = i->scheme->fmt; r->fmt_storage = i->scheme->fmt_storage; sdsnapshot snapshot; sd_snapshot_init(&snapshot); rc = si_recoversnapshot(i, r, &snapshot); if (ssunlikely(rc == -1)) { sd_snapshot_free(&snapshot, r); return -1; } rc = si_recoverindex(i, r, &snapshot); sd_snapshot_free(&snapshot, r); if (sslikely(rc <= 0)) return rc; deploy: return si_deploy(i, r, !exist); }
int sy_open(sy *e, sr *r, syconf *conf) { e->conf = conf; int rc = sy_recoverbackup(e, r); if (ssunlikely(rc == -1)) return -1; int exists = ss_vfsexists(r->vfs, conf->path); if (exists == 0) return sy_deploy(e, r); return 0; }
int sy_open(sy *e, sr *r, syconf *conf) { e->conf = conf; int rc = sy_recoverbackup(e, r); if (ssunlikely(rc == -1)) return -1; int exists = ss_vfsexists(r->vfs, conf->path); if (exists == 0) { if (ssunlikely(! conf->path_create)) { sr_error(r->e, "directory '%s' does not exist", conf->path); return -1; } return sy_deploy(e, r); } return 0; }
static inline int si_recoverdrop(si *i, sr *r) { char path[1024]; snprintf(path, sizeof(path), "%s/drop", i->scheme->path); int rc = ss_vfsexists(r->vfs, path); if (sslikely(! rc)) return 0; if (i->scheme->path_fail_on_drop) { sr_malfunction(r->e, "attempt to recover a dropped database: %s:", i->scheme->path); return -1; } rc = si_droprepository(i->scheme, r, 0); if (ssunlikely(rc == -1)) return -1; return 1; }
static inline int si_tracksnapshot(sitrack *track, sr *r, si *i, sdsnapshot *s) { /* read snapshot */ ssiter iter; ss_iterinit(sd_snapshotiter, &iter); int rc; rc = ss_iteropen(sd_snapshotiter, &iter, r, s); if (ssunlikely(rc == -1)) return -1; for (; ss_iterhas(sd_snapshotiter, &iter); ss_iternext(sd_snapshotiter, &iter)) { sdsnapshotnode *n = ss_iterof(sd_snapshotiter, &iter); /* skip updated nodes */ sspath path; ss_path(&path, i->scheme->path, n->id, ".db"); rc = ss_vfsexists(r->vfs, path.path); if (! rc) continue; uint64_t size = ss_vfssize(r->vfs, path.path); if (size != n->size_file) continue; /* recover node */ sinode *node = si_nodenew(r); if (ssunlikely(node == NULL)) return -1; node->recover = SI_RDB; rc = si_nodeopen(node, r, i->scheme, &path, n); if (ssunlikely(rc == -1)) { si_nodefree(node, r, 0); return -1; } si_trackmetrics(track, node); si_trackset(track, node); } /* recover index temperature (read stats) */ sdsnapshotheader *h = sd_snapshot_header(s); i->read_cache = h->read_cache; i->read_disk = h->read_disk; i->lru_v = h->lru_v; i->lru_steps = h->lru_steps; return 0; }
static inline int sy_recoverbackup(sy *i, sr *r) { if (i->conf->path_backup == NULL) return 0; int rc; int exists = ss_vfsexists(r->vfs, i->conf->path_backup); if (! exists) { rc = ss_vfsmkdir(r->vfs, i->conf->path_backup, 0755); if (ssunlikely(rc == -1)) { sr_error(r->e, "backup directory '%s' create error: %s", i->conf->path_backup, strerror(errno)); return -1; } } /* recover backup sequential number */ DIR *dir = opendir(i->conf->path_backup); if (ssunlikely(dir == NULL)) { sr_error(r->e, "backup directory '%s' open error: %s", i->conf->path_backup, strerror(errno)); return -1; } uint32_t bsn = 0; struct dirent *de; while ((de = readdir(dir))) { if (ssunlikely(de->d_name[0] == '.')) continue; uint32_t id = 0; rc = sy_process(de->d_name, &id); switch (rc) { case 1: case 0: if (id > bsn) bsn = id; break; case -1: /* skip unknown file */ continue; } } closedir(dir); r->seq->bsn = bsn; return 0; }
static inline int si_recoversnapshot(si *i, sr *r, sdsnapshot *s) { /* recovery stages: snapshot (1) ok snapshot.incomplete (2) remove snapshot.incomplete snapshot (3) remove snapshot.incomplete, load snapshot snapshot.incomplete */ /* recover snapshot file (crash recover) */ int snapshot = 0; int snapshot_incomplete = 0; char path[1024]; snprintf(path, sizeof(path), "%s/index", i->scheme->path); snapshot = ss_vfsexists(r->vfs, path); snprintf(path, sizeof(path), "%s/index.incomplete", i->scheme->path); snapshot_incomplete = ss_vfsexists(r->vfs, path); int rc; if (snapshot_incomplete) { rc = ss_vfsunlink(r->vfs, path); if (ssunlikely(rc == -1)) { sr_malfunction(r->e, "index file '%s' unlink error: %s", path, strerror(errno)); return -1; } } if (! snapshot) return 0; /* read snapshot file */ snprintf(path, sizeof(path), "%s/index", i->scheme->path); ssize_t size = ss_vfssize(r->vfs, path); if (ssunlikely(size == -1)) { sr_malfunction(r->e, "index file '%s' read error: %s", path, strerror(errno)); return -1; } rc = ss_bufensure(&s->buf, r->a, size); if (ssunlikely(rc == -1)) return sr_oom_malfunction(r->e); ssfile file; ss_fileinit(&file, r->vfs); rc = ss_fileopen(&file, path); if (ssunlikely(rc == -1)) { sr_malfunction(r->e, "index file '%s' open error: %s", path, strerror(errno)); return -1; } rc = ss_filepread(&file, 0, s->buf.s, size); if (ssunlikely(rc == -1)) { sr_malfunction(r->e, "index file '%s' read error: %s", path, strerror(errno)); ss_fileclose(&file); return -1; } ss_bufadvance(&s->buf, size); ss_fileclose(&file); return 0; }