#define DB_NAME "context-job-scheduler"
#define JOB_INFO_TABLE "PersistentJobInfo"
+#define USED_ID_TABLE "UsedJobId"
#define ST_STARTED "started"
using namespace ctx;
return tableName;
}
-static void __init_database(uid_t uid)
+static void __create_used_id_table()
{
+ __database->execute(
+ "CREATE TABLE IF NOT EXISTS " USED_ID_TABLE " (jobId INTEGER PRIMARY KEY)",
+ NULL);
+}
+
+static void __create_job_info_table(uid_t uid)
+{
+ const char* tableName = __get_table_name(uid);
char* query = sqlite3_mprintf(
"CREATE TABLE IF NOT EXISTS [%s] (" \
"jobId INTEGER NOT NULL PRIMARY KEY," \
"owner TEXT NOT NULL," \
"jobInfo TEXT NOT NULL," \
- "state TEXT NOT NULL DEFAULT ''" \
- ")", __get_table_name(uid));
+ "state TEXT NOT NULL DEFAULT ''); " \
+ "CREATE TRIGGER IF NOT EXISTS [%s_Insert] AFTER INSERT ON [%s] " \
+ "BEGIN " \
+ "INSERT INTO " USED_ID_TABLE " (jobId) VALUES (NEW.jobId); " \
+ "END; " \
+ "CREATE TRIGGER IF NOT EXISTS [%s_Delete] AFTER DELETE ON [%s] " \
+ "BEGIN " \
+ "DELETE FROM " USED_ID_TABLE " WHERE (jobId = OLD.jobId); " \
+ "END;",
+ tableName, tableName, tableName, tableName, tableName);
__database->execute(query, NULL);
_E("DB open failed");
return false;
}
+
+ __create_used_id_table();
}
- __init_database(uid);
+ __create_job_info_table(uid);
++__numDBConnection;
return true;
return jobInfos;
}
+
+bool JobInfoDatabase::getUsedIds(std::vector<std::shared_ptr<Tuple>>* usedIds)
+{
+ std::vector<std::string> columns = {"jobId"};
+
+ return __database->execute(
+ "SELECT jobId FROM " USED_ID_TABLE " ORDER BY jobID ASC",
+ COL_INT64, &columns, usedIds);
+}
* limitations under the License.
*/
+#include <deque>
#include <ServerUtil.h>
#include <JobAction.h>
#include "SchedTimer.h"
using namespace ctx;
-static int __lastJobId = 0;
+namespace {
+ class JobIdGenerator {
+ public:
+ void init(JobInfoDatabase& database);
+ int pop();
+ private:
+ void __push(int id);
+ std::deque<int> __usedIds;
+ };
+}
+
+void JobIdGenerator::init(JobInfoDatabase& database)
+{
+ IF_FAIL_VOID(__usedIds.empty());
+
+ int64_t id = 0;
+ std::vector<std::shared_ptr<Tuple>> usedIds;
+ database.getUsedIds(&usedIds);
+ __usedIds.push_back(0);
+
+ for (auto& tuple : usedIds) {
+ if (tuple->getAt(0, &id))
+ __push(static_cast<int>(id));
+ }
+}
+
+int JobIdGenerator::pop()
+{
+ int nextId = ++(__usedIds.front());
+
+ while (__usedIds[1] == __usedIds[0] + 1) {
+ __usedIds.pop_front();
+ }
+
+ return nextId;
+}
+
+void JobIdGenerator::__push(int id)
+{
+ __usedIds.push_back(id);
+
+ if (__usedIds[1] == __usedIds[0] + 1)
+ __usedIds.pop_front();
+}
+
+static JobIdGenerator __jobIdGenerator;
JobManager::JobManager(uid_t uid) :
__uid(uid),
__jobInfoDatabase(uid)
{
_I("Initialize JobManager-%u", static_cast<unsigned>(__uid));
+ __jobIdGenerator.init(__jobInfoDatabase);
__restore();
}
{
__verifyPeriodicJob(jobInfo, owner);
- jobInfo->setId(__generateJobId());
+ jobInfo->setId(__jobIdGenerator.pop());
unsigned int cnt = __addRunner(new PeriodicJobRunner(this, owner->getName(), jobInfo));
_D("%u jobs have been registered", cnt);
{
__verifyOnDemandJob(jobInfo, owner);
- jobInfo->setId(__generateJobId());
+ jobInfo->setId(__jobIdGenerator.pop());
unsigned int cnt = __addRunner(new OnDemandJobRunner(this, owner->getName(), jobInfo));
_D("%u jobs have been registered", cnt);
throw static_cast<int>(E_PARAM);
}
-
-
-int JobManager::__generateJobId()
-{
- if (++__lastJobId < 0)
- __lastJobId = 1;
-
- return __lastJobId;
-}
-
unsigned int JobManager::__addRunner(JobRunner* runner)
{
__jobRunners.push_back(runner);
void JobManager::__restore()
{
- int maxJobId = 0;
auto storedJobs = __jobInfoDatabase.getAll();
_I("Restoring %u jobs", storedJobs.size());
const std::string& owner = storedJob.first;
JobInfo* jobInfo = storedJob.second;
- maxJobId = MAX(maxJobId, jobInfo->getId());
-
JobRunner* runner = NULL;
if (jobInfo->getType() == JobInfo::Type::PERIODIC)
runner = new PeriodicJobRunner(this, owner, jobInfo);
}
SchedTimer::resume();
-
- __lastJobId = maxJobId;
}
void JobManager::__release()