void Indexer_commit(Indexer *self) { // Safety check. if ( !self->write_lock ) { THROW(ERR, "Can't call commit() more than once"); } if (!self->prepared) { Indexer_Prepare_Commit(self); } if (self->needs_commit) { bool_t success; // Rename temp snapshot file. CharBuf *temp_snapfile = CB_Clone(self->snapfile); CB_Chop(self->snapfile, sizeof(".temp") - 1); Snapshot_Set_Path(self->snapshot, self->snapfile); success = Folder_Rename(self->folder, temp_snapfile, self->snapfile); DECREF(temp_snapfile); if (!success) { RETHROW(INCREF(Err_get_error())); } // Purge obsolete files. FilePurger_Purge(self->file_purger); } // Release locks, invalidating the Indexer. S_release_merge_lock(self); S_release_write_lock(self); }
void BGMerger_Commit_IMP(BackgroundMerger *self) { BackgroundMergerIVARS *const ivars = BGMerger_IVARS(self); // Safety check. if (!ivars->merge_lock) { THROW(ERR, "Can't call commit() more than once"); } if (!ivars->prepared) { BGMerger_Prepare_Commit(self); } if (ivars->needs_commit) { bool success = false; String *temp_snapfile = ivars->snapfile; // Rename temp snapshot file. size_t ext_len = sizeof(".temp") - 1; size_t snapfile_len = Str_Length(temp_snapfile); if (snapfile_len <= ext_len) { THROW(ERR, "Invalid snapfile name: %o", temp_snapfile); } ivars->snapfile = Str_SubString(temp_snapfile, 0, snapfile_len - ext_len); success = Folder_Hard_Link(ivars->folder, temp_snapfile, ivars->snapfile); Snapshot_Set_Path(ivars->snapshot, ivars->snapfile); if (!success) { String *mess = Str_newf("Can't create hard link from %o to %o", temp_snapfile, ivars->snapfile); DECREF(temp_snapfile); Err_throw_mess(ERR, mess); } if (!Folder_Delete(ivars->folder, temp_snapfile)) { String *mess = Str_newf("Can't delete %o", temp_snapfile); DECREF(temp_snapfile); Err_throw_mess(ERR, mess); } DECREF(temp_snapfile); } // Release the merge lock and remove the merge data file. S_release_merge_lock(self); IxManager_Remove_Merge_Data(ivars->manager); if (ivars->needs_commit) { // Purge obsolete files. FilePurger_Purge(ivars->file_purger); } // Release the write lock. S_release_write_lock(self); }
void Indexer_destroy(Indexer *self) { S_release_merge_lock(self); S_release_write_lock(self); DECREF(self->schema); DECREF(self->folder); DECREF(self->segment); DECREF(self->manager); DECREF(self->stock_doc); DECREF(self->polyreader); DECREF(self->del_writer); DECREF(self->snapshot); DECREF(self->seg_writer); DECREF(self->file_purger); DECREF(self->write_lock); DECREF(self->snapfile); SUPER_DESTROY(self, INDEXER); }
void BGMerger_Destroy_IMP(BackgroundMerger *self) { BackgroundMergerIVARS *const ivars = BGMerger_IVARS(self); S_release_merge_lock(self); S_release_write_lock(self); DECREF(ivars->schema); DECREF(ivars->folder); DECREF(ivars->segment); DECREF(ivars->manager); DECREF(ivars->polyreader); DECREF(ivars->del_writer); DECREF(ivars->snapshot); DECREF(ivars->seg_writer); DECREF(ivars->file_purger); DECREF(ivars->write_lock); DECREF(ivars->snapfile); DECREF(ivars->doc_maps); SUPER_DESTROY(self, BACKGROUNDMERGER); }
void Indexer_Destroy_IMP(Indexer *self) { IndexerIVARS *const ivars = Indexer_IVARS(self); S_release_merge_lock(self); S_release_write_lock(self); DECREF(ivars->schema); DECREF(ivars->folder); DECREF(ivars->segment); DECREF(ivars->manager); DECREF(ivars->stock_doc); DECREF(ivars->polyreader); DECREF(ivars->del_writer); DECREF(ivars->snapshot); DECREF(ivars->seg_writer); DECREF(ivars->file_purger); DECREF(ivars->write_lock); DECREF(ivars->snapfile); SUPER_DESTROY(self, INDEXER); }
void Indexer_Commit_IMP(Indexer *self) { IndexerIVARS *const ivars = Indexer_IVARS(self); // Safety check. if (!ivars->write_lock) { THROW(ERR, "Can't call commit() more than once"); } if (!ivars->prepared) { Indexer_Prepare_Commit(self); } if (ivars->needs_commit) { bool success; // Rename temp snapshot file. String *temp_snapfile = ivars->snapfile; size_t ext_len = sizeof(".temp") - 1; size_t snapfile_len = Str_Length(temp_snapfile); if (snapfile_len <= ext_len) { THROW(ERR, "Invalid snapfile name: %o", temp_snapfile); } ivars->snapfile = Str_SubString(temp_snapfile, 0, snapfile_len - ext_len); Snapshot_Set_Path(ivars->snapshot, ivars->snapfile); success = Folder_Rename(ivars->folder, temp_snapfile, ivars->snapfile); DECREF(temp_snapfile); if (!success) { RETHROW(INCREF(Err_get_error())); } // Purge obsolete files. FilePurger_Purge(ivars->file_purger); } // Release locks, invalidating the Indexer. S_release_merge_lock(self); S_release_write_lock(self); }
BackgroundMerger* BGMerger_init(BackgroundMerger *self, Obj *index, IndexManager *manager) { BackgroundMergerIVARS *const ivars = BGMerger_IVARS(self); Folder *folder = S_init_folder(index); // Init. ivars->optimize = false; ivars->prepared = false; ivars->needs_commit = false; ivars->snapfile = NULL; ivars->doc_maps = Hash_new(0); // Assign. ivars->folder = folder; if (manager) { ivars->manager = (IndexManager*)INCREF(manager); } else { ivars->manager = IxManager_new(NULL, NULL); IxManager_Set_Write_Lock_Timeout(ivars->manager, 10000); } IxManager_Set_Folder(ivars->manager, folder); // Obtain write lock (which we'll only hold briefly), then merge lock. S_obtain_write_lock(self); if (!ivars->write_lock) { DECREF(self); RETHROW(INCREF(Err_get_error())); } S_obtain_merge_lock(self); if (!ivars->merge_lock) { DECREF(self); RETHROW(INCREF(Err_get_error())); } // Find the latest snapshot. If there's no index content, bail early. ivars->snapshot = Snapshot_Read_File(Snapshot_new(), folder, NULL); if (!Snapshot_Get_Path(ivars->snapshot)) { S_release_write_lock(self); S_release_merge_lock(self); return self; } // Create FilePurger. Zap detritus from previous sessions. ivars->file_purger = FilePurger_new(folder, ivars->snapshot, ivars->manager); FilePurger_Purge(ivars->file_purger); // Open a PolyReader, passing in the IndexManager so we get a read lock on // the Snapshot's files -- so that Indexers don't zap our files while // we're operating in the background. ivars->polyreader = PolyReader_open((Obj*)folder, NULL, ivars->manager); // Clone the PolyReader's schema. Obj *dump = (Obj*)Schema_Dump(PolyReader_Get_Schema(ivars->polyreader)); ivars->schema = (Schema*)CERTIFY(Freezer_load(dump), SCHEMA); DECREF(dump); // Create new Segment. int64_t new_seg_num = IxManager_Highest_Seg_Num(ivars->manager, ivars->snapshot) + 1; Vector *fields = Schema_All_Fields(ivars->schema); ivars->segment = Seg_new(new_seg_num); for (uint32_t i = 0, max = Vec_Get_Size(fields); i < max; i++) { Seg_Add_Field(ivars->segment, (String*)Vec_Fetch(fields, i)); } DECREF(fields); // Our "cutoff" is the segment this BackgroundMerger will write. Now that // we've determined the cutoff, write the merge data file. ivars->cutoff = Seg_Get_Number(ivars->segment); IxManager_Write_Merge_Data(ivars->manager, ivars->cutoff); /* Create the SegWriter but hold off on preparing the new segment * directory -- because if we don't need to merge any segments we don't * need it. (We've reserved the dir by plopping down the merge.json * file.) */ ivars->seg_writer = SegWriter_new(ivars->schema, ivars->snapshot, ivars->segment, ivars->polyreader); // Grab a local ref to the DeletionsWriter. ivars->del_writer = (DeletionsWriter*)INCREF(SegWriter_Get_Del_Writer(ivars->seg_writer)); // Release the write lock. Now new Indexers can start while we work in // the background. S_release_write_lock(self); return self; }