]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/migrate.c
kes Apply Maritn's fix to src/win32/Makefile.
[bacula/bacula] / bacula / src / dird / migrate.c
1 /*
2  *
3  *   Bacula Director -- migrate.c -- responsible for doing
4  *     migration jobs.
5  *
6  *     Kern Sibbald, September MMIV
7  *
8  *  Basic tasks done here:
9  *     Open DB and create records for this job.
10  *     Open Message Channel with Storage daemon to tell him a job will be starting.
11  *     Open connection with Storage daemon and pass him commands
12  *       to do the backup.
13  *     When the Storage daemon finishes the job, update the DB.
14  *
15  *   Version $Id$
16  */
17 /*
18    Copyright (C) 2004-2006 Kern Sibbald
19
20    This program is free software; you can redistribute it and/or
21    modify it under the terms of the GNU General Public License
22    version 2 as amended with additional clauses defined in the
23    file LICENSE in the main source directory.
24
25    This program is distributed in the hope that it will be useful,
26    but WITHOUT ANY WARRANTY; without even the implied warranty of
27    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
28    the file LICENSE for additional details.
29
30  */
31
32 #include "bacula.h"
33 #include "dird.h"
34 #include "ua.h"
35 #ifndef HAVE_REGEX_H
36 #include "lib/bregex.h"
37 #else
38 #include <regex.h>
39 #endif
40
41 static const int dbglevel = 100;
42
43 static char OKbootstrap[] = "3000 OK bootstrap\n";
44 static bool get_job_to_migrate(JCR *jcr);
45 struct idpkt;
46 static bool regex_find_jobids(JCR *jcr, idpkt *ids, const char *query1,
47                  const char *query2, const char *type);
48 static bool find_mediaid_then_jobids(JCR *jcr, idpkt *ids, const char *query1,
49                  const char *type);
50 static bool find_jobids_from_mediaid_list(JCR *jcr, idpkt *ids, const char *type);
51 static void start_migration_job(JCR *jcr);
52 static int get_next_dbid_from_list(char **p, DBId_t *DBId);
53
54 /* 
55  * Called here before the job is run to do the job
56  *   specific setup.
57  */
58 bool do_migration_init(JCR *jcr)
59 {
60    /* If we find a job or jobs to migrate it is previous_jr.JobId */
61    if (!get_job_to_migrate(jcr)) {
62       return false;
63    }
64
65    if (jcr->previous_jr.JobId == 0) {
66       return true;                    /* no work */
67    }
68
69    if (!get_or_create_fileset_record(jcr)) {
70       return false;
71    }
72
73    apply_pool_overrides(jcr);
74
75    jcr->jr.PoolId = get_or_create_pool_record(jcr, jcr->pool->hdr.name);
76    if (jcr->jr.PoolId == 0) {
77       return false;
78    }
79
80    /* If pool storage specified, use it instead of job storage */
81    copy_wstorage(jcr, jcr->pool->storage, _("Pool resource"));
82
83    if (!jcr->wstorage) {
84       Jmsg(jcr, M_FATAL, 0, _("No Storage specification found in Job or Pool.\n"));
85       return false;
86    }
87
88    create_restore_bootstrap_file(jcr);
89    return true;
90 }
91
92 /*
93  * Do a Migration of a previous job
94  *
95  *  Returns:  false on failure
96  *            true  on success
97  */
98 bool do_migration(JCR *jcr)
99 {
100    POOL_DBR pr;
101    POOL *pool;
102    char ed1[100];
103    BSOCK *sd;
104    JOB *job, *prev_job;
105    JCR *mig_jcr;                   /* newly migrated job */
106
107    /* 
108     *  previous_jr refers to the job DB record of the Job that is
109     *    going to be migrated.
110     *  prev_job refers to the job resource of the Job that is
111     *    going to be migrated.
112     *  jcr is the jcr for the current "migration" job.  It is a
113     *    control job that is put in the DB as a migration job, which
114     *    means that this job migrated a previous job to a new job.
115     *    No Volume or File data is associated with this control
116     *    job.
117     *  mig_jcr refers to the newly migrated job that is run by
118     *    the current jcr.  It is a backup job that moves (migrates) the
119     *    data written for the previous_jr into the new pool.  This
120     *    job (mig_jcr) becomes the new backup job that replaces
121     *    the original backup job.
122     */
123    if (jcr->previous_jr.JobId == 0 || jcr->ExpectedFiles == 0) {
124       set_jcr_job_status(jcr, JS_Terminated);
125       migration_cleanup(jcr, jcr->JobStatus);
126       return true;                    /* no work */
127    }
128
129    Dmsg4(dbglevel, "Previous: Name=%s JobId=%d Type=%c Level=%c\n",
130       jcr->previous_jr.Name, jcr->previous_jr.JobId, 
131       jcr->previous_jr.JobType, jcr->previous_jr.JobLevel);
132
133    Dmsg4(dbglevel, "Current: Name=%s JobId=%d Type=%c Level=%c\n",
134       jcr->jr.Name, jcr->jr.JobId, 
135       jcr->jr.JobType, jcr->jr.JobLevel);
136
137    LockRes();
138    job = (JOB *)GetResWithName(R_JOB, jcr->jr.Name);
139    prev_job = (JOB *)GetResWithName(R_JOB, jcr->previous_jr.Name);
140    UnlockRes();
141    if (!job || !prev_job) {
142       return false;
143    }
144
145    /* Create a migation jcr */
146    mig_jcr = jcr->mig_jcr = new_jcr(sizeof(JCR), dird_free_jcr);
147    memcpy(&mig_jcr->previous_jr, &jcr->previous_jr, sizeof(mig_jcr->previous_jr));
148
149    /*
150     * Turn the mig_jcr into a "real" job that takes on the aspects of
151     *   the previous backup job "prev_job".
152     */
153    set_jcr_defaults(mig_jcr, prev_job);
154    if (!setup_job(mig_jcr)) {
155       return false;
156    }
157
158    /* Now reset the job record from the previous job */
159    memcpy(&mig_jcr->jr, &jcr->previous_jr, sizeof(mig_jcr->jr));
160    /* Update the jr to reflect the new values of PoolId, FileSetId, and JobId. */
161    mig_jcr->jr.PoolId = jcr->jr.PoolId;
162    mig_jcr->jr.FileSetId = jcr->jr.FileSetId;
163    mig_jcr->jr.JobId = mig_jcr->JobId;
164
165    Dmsg4(dbglevel, "mig_jcr: Name=%s JobId=%d Type=%c Level=%c\n",
166       mig_jcr->jr.Name, mig_jcr->jr.JobId, 
167       mig_jcr->jr.JobType, mig_jcr->jr.JobLevel);
168
169    /*
170     * Get the PoolId used with the original job. Then
171     *  find the pool name from the database record.
172     */
173    memset(&pr, 0, sizeof(pr));
174    pr.PoolId = mig_jcr->previous_jr.PoolId;
175    if (!db_get_pool_record(jcr, jcr->db, &pr)) {
176       Jmsg(jcr, M_FATAL, 0, _("Pool for JobId %s not in database. ERR=%s\n"),
177             edit_int64(pr.PoolId, ed1), db_strerror(jcr->db));
178          return false;
179    }
180    /* Get the pool resource corresponding to the original job */
181    pool = (POOL *)GetResWithName(R_POOL, pr.Name);
182    if (!pool) {
183       Jmsg(jcr, M_FATAL, 0, _("Pool resource \"%s\" not found.\n"), pr.Name);
184       return false;
185    }
186
187    /* If pool storage specified, use it for restore */
188    copy_rstorage(mig_jcr, pool->storage, _("Pool resource"));
189    copy_rstorage(jcr, pool->storage, _("Pool resource"));
190
191    /*
192     * If the original backup pool has a NextPool, make sure a 
193     *  record exists in the database. Note, in this case, we
194     *  will be migrating from pool to pool->NextPool.
195     */
196    if (pool->NextPool) {
197       jcr->jr.PoolId = get_or_create_pool_record(jcr, pool->NextPool->hdr.name);
198       if (jcr->jr.PoolId == 0) {
199          return false;
200       }
201       /*
202        * put the "NextPool" resource pointer in our jcr so that we
203        * can pull the Storage reference from it.
204        */
205       mig_jcr->pool = jcr->pool = pool->NextPool;
206       mig_jcr->jr.PoolId = jcr->jr.PoolId;
207       pm_strcpy(jcr->pool_source, _("NextPool in Pool resource"));
208    }
209
210    /* If pool storage specified, use it instead of job storage for backup */
211    copy_wstorage(jcr, jcr->pool->storage, _("Pool resource"));
212
213    /* Print Job Start message */
214    Jmsg(jcr, M_INFO, 0, _("Start Migration JobId %s, Job=%s\n"),
215         edit_uint64(jcr->JobId, ed1), jcr->Job);
216
217    set_jcr_job_status(jcr, JS_Running);
218    set_jcr_job_status(mig_jcr, JS_Running);
219    Dmsg2(dbglevel, "JobId=%d JobLevel=%c\n", jcr->jr.JobId, jcr->jr.JobLevel);
220
221    /* Update job start record for this migration control job */
222    if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
223       Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
224       return false;
225    }
226
227    Dmsg4(dbglevel, "mig_jcr: Name=%s JobId=%d Type=%c Level=%c\n",
228       mig_jcr->jr.Name, mig_jcr->jr.JobId, 
229       mig_jcr->jr.JobType, mig_jcr->jr.JobLevel);
230
231    /* Update job start record for the real migration backup job */
232    if (!db_update_job_start_record(mig_jcr, mig_jcr->db, &mig_jcr->jr)) {
233       Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(mig_jcr->db));
234       return false;
235    }
236
237
238    /*
239     * Open a message channel connection with the Storage
240     * daemon. This is to let him know that our client
241     * will be contacting him for a backup  session.
242     *
243     */
244    Dmsg0(110, "Open connection with storage daemon\n");
245    set_jcr_job_status(jcr, JS_WaitSD);
246    set_jcr_job_status(mig_jcr, JS_WaitSD);
247    /*
248     * Start conversation with Storage daemon
249     */
250    if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) {
251       return false;
252    }
253    sd = jcr->store_bsock;
254    /*
255     * Now start a job with the Storage daemon
256     */
257    Dmsg2(dbglevel, "Read store=%s, write store=%s\n", 
258       ((STORE *)jcr->rstorage->first())->name(),
259       ((STORE *)jcr->wstorage->first())->name());
260    if (!start_storage_daemon_job(jcr, jcr->rstorage, jcr->wstorage)) {
261       return false;
262    }
263    Dmsg0(150, "Storage daemon connection OK\n");
264
265    if (!send_bootstrap_file(jcr, sd) ||
266        !response(jcr, sd, OKbootstrap, "Bootstrap", DISPLAY_ERROR)) {
267       return false;
268    }
269
270    if (!bnet_fsend(sd, "run")) {
271       return false;
272    }
273
274    /*
275     * Now start a Storage daemon message thread
276     */
277    if (!start_storage_daemon_message_thread(jcr)) {
278       return false;
279    }
280
281
282    set_jcr_job_status(jcr, JS_Running);
283    set_jcr_job_status(mig_jcr, JS_Running);
284
285    /* Pickup Job termination data */
286    /* Note, the SD stores in jcr->JobFiles/ReadBytes/JobBytes/Errors */
287    wait_for_storage_daemon_termination(jcr);
288
289    set_jcr_job_status(jcr, jcr->SDJobStatus);
290    if (jcr->JobStatus != JS_Terminated) {
291       return false;
292    }
293    migration_cleanup(jcr, jcr->JobStatus);
294    if (mig_jcr) {
295       UAContext *ua = new_ua_context(jcr);
296       purge_files_from_job(ua, jcr->previous_jr.JobId);
297       free_ua_context(ua);
298    }
299    return true;
300 }
301
302 struct idpkt {
303    POOLMEM *list;
304    uint32_t count;
305 };
306
307 /*
308  * Callback handler make list of DB Ids
309  */
310 static int dbid_handler(void *ctx, int num_fields, char **row)
311 {
312    idpkt *ids = (idpkt *)ctx;
313
314    Dmsg3(dbglevel, "count=%d Ids=%p %s\n", ids->count, ids->list, ids->list);
315    if (ids->count == 0) {
316       ids->list[0] = 0;
317    } else {
318       pm_strcat(ids->list, ",");
319    }
320    pm_strcat(ids->list, row[0]);
321    ids->count++;
322    return 0;
323 }
324
325
326 struct uitem {
327    dlink link;   
328    char *item;
329 };
330
331 static int item_compare(void *item1, void *item2)
332 {
333    uitem *i1 = (uitem *)item1;
334    uitem *i2 = (uitem *)item2;
335    return strcmp(i1->item, i2->item);
336 }
337
338 static int unique_name_handler(void *ctx, int num_fields, char **row)
339 {
340    dlist *list = (dlist *)ctx;
341
342    uitem *new_item = (uitem *)malloc(sizeof(uitem));
343    uitem *item;
344    
345    memset(new_item, 0, sizeof(uitem));
346    new_item->item = bstrdup(row[0]);
347    Dmsg1(dbglevel, "Item=%s\n", row[0]);
348    item = (uitem *)list->binary_insert((void *)new_item, item_compare);
349    if (item != new_item) {            /* already in list */
350       free(new_item->item);
351       free((char *)new_item);
352       return 0;
353    }
354    return 0;
355 }
356
357 /* Get Job names in Pool */
358 const char *sql_job =
359    "SELECT DISTINCT Job.Name from Job,Pool"
360    " WHERE Pool.Name='%s' AND Job.PoolId=Pool.PoolId";
361
362 /* Get JobIds from regex'ed Job names */
363 const char *sql_jobids_from_job =
364    "SELECT DISTINCT Job.JobId,Job.StartTime FROM Job,Pool"
365    " WHERE Job.Name='%s' AND Pool.Name='%s' AND Job.PoolId=Pool.PoolId"
366    " ORDER by Job.StartTime";
367
368 /* Get Client names in Pool */
369 const char *sql_client =
370    "SELECT DISTINCT Client.Name from Client,Pool,Job"
371    " WHERE Pool.Name='%s' AND Job.ClientId=Client.ClientId AND"
372    " Job.PoolId=Pool.PoolId";
373
374 /* Get JobIds from regex'ed Client names */
375 const char *sql_jobids_from_client =
376    "SELECT DISTINCT Job.JobId,Job.StartTime FROM Job,Pool"
377    " WHERE Client.Name='%s' AND Pool.Name='%s' AND Job.PoolId=Pool.PoolId"
378    " AND Job.ClientId=Client.ClientId "
379    " ORDER by Job.StartTime";
380
381 /* Get Volume names in Pool */
382 const char *sql_vol = 
383    "SELECT DISTINCT VolumeName FROM Media,Pool WHERE"
384    " VolStatus in ('Full','Used','Error') AND Media.Enabled=1 AND"
385    " Media.PoolId=Pool.PoolId AND Pool.Name='%s'";
386
387 /* Get JobIds from regex'ed Volume names */
388 const char *sql_jobids_from_vol =
389    "SELECT DISTINCT Job.JobId,Job.StartTime FROM Media,JobMedia,Job"
390    " WHERE Media.VolumeName='%s' AND Media.MediaId=JobMedia.MediaId"
391    " AND JobMedia.JobId=Job.JobId" 
392    " ORDER by Job.StartTime";
393
394
395 const char *sql_smallest_vol = 
396    "SELECT MediaId FROM Media,Pool WHERE"
397    " VolStatus in ('Full','Used','Error') AND Media.Enabled=1 AND"
398    " Media.PoolId=Pool.PoolId AND Pool.Name='%s'"
399    " ORDER BY VolBytes ASC LIMIT 1";
400
401 const char *sql_oldest_vol = 
402    "SELECT MediaId FROM Media,Pool WHERE"
403    " VolStatus in ('Full','Used','Error') AND Media.Enabled=1 AND"
404    " Media.PoolId=Pool.PoolId AND Pool.Name='%s'"
405    " ORDER BY LastWritten ASC LIMIT 1";
406
407 /* Get JobIds when we have selected MediaId */
408 const char *sql_jobids_from_mediaid =
409    "SELECT DISTINCT Job.JobId,Job.StartTime FROM JobMedia,Job"
410    " WHERE JobMedia.JobId=Job.JobId AND JobMedia.MediaId=%s"
411    " ORDER by Job.StartTime";
412
413 /* Get tne number of bytes in the pool */
414 const char *sql_pool_bytes =
415    "SELECT SUM(VolBytes) FROM Media,Pool WHERE"
416    " VolStatus in ('Full','Used','Error','Append') AND Media.Enabled=1 AND"
417    " Media.PoolId=Pool.PoolId AND Pool.Name='%s'";
418
419 /* Get tne number of bytes in the Jobs */
420 const char *sql_job_bytes =
421    "SELECT SUM(JobBytes) FROM Job WHERE JobId IN (%s)";
422
423
424 /* Get Media Ids in Pool */
425 const char *sql_mediaids =
426    "SELECT MediaId FROM Media,Pool WHERE"
427    " VolStatus in ('Full','Used','Error') AND Media.Enabled=1 AND"
428    " Media.PoolId=Pool.PoolId AND Pool.Name='%s' ORDER BY LastWritten ASC";
429
430 /* Get JobIds in Pool longer than specified time */
431 const char *sql_pool_time = 
432    "SELECT DISTINCT Job.JobId from Pool,Job,Media,JobMedia WHERE"
433    " Pool.Name='%s' AND Media.PoolId=Pool.PoolId AND"
434    " VolStatus in ('Full','Used','Error') AND Media.Enabled=1 AND"
435    " JobMedia.JobId=Job.JobId AND Job.PoolId=Media.PoolId"
436    " AND Job.RealEndTime<='%s'";
437
438 /*
439 * const char *sql_ujobid =
440 *   "SELECT DISTINCT Job.Job from Client,Pool,Media,Job,JobMedia "
441 *   " WHERE Media.PoolId=Pool.PoolId AND Pool.Name='%s' AND"
442 *   " JobMedia.JobId=Job.JobId AND Job.PoolId=Media.PoolId";
443 */
444
445
446
447 /*
448  *
449  * This is the central piece of code that finds a job or jobs 
450  *   actually JobIds to migrate.  It first looks to see if one
451  *   has been "manually" specified in jcr->MigrateJobId, and if
452  *   so, it returns that JobId to be run.  Otherwise, it
453  *   examines the Selection Type to see what kind of migration
454  *   we are doing (Volume, Job, Client, ...) and applies any
455  *   Selection Pattern if appropriate to obtain a list of JobIds.
456  *   Finally, it will loop over all the JobIds found, except the last
457  *   one starting a new job with MigrationJobId set to that JobId, and
458  *   finally, it returns the last JobId to the caller.
459  *
460  * Returns: false on error
461  *          true  if OK and jcr->previous_jr filled in
462  */
463 static bool get_job_to_migrate(JCR *jcr)
464 {
465    char ed1[30];
466    POOL_MEM query(PM_MESSAGE);
467    JobId_t JobId;
468    DBId_t  MediaId = 0;
469    int stat;
470    char *p;
471    idpkt ids, mid, jids;
472    db_int64_ctx ctx;
473    int64_t pool_bytes;
474    bool ok;
475    time_t ttime;
476    struct tm tm;
477    char dt[MAX_TIME_LENGTH];
478
479    ids.list = get_pool_memory(PM_MESSAGE);
480    ids.list[0] = 0;
481    ids.count = 0;
482    mid.list = get_pool_memory(PM_MESSAGE);
483    mid.list[0] = 0;
484    mid.count = 0;
485    jids.list = get_pool_memory(PM_MESSAGE);
486    jids.list[0] = 0;
487    jids.count = 0;
488
489
490    /*
491     * If MigrateJobId is set, then we migrate only that Job,
492     *  otherwise, we go through the full selection of jobs to
493     *  migrate.
494     */
495    if (jcr->MigrateJobId != 0) {
496       Dmsg1(dbglevel, "At Job start previous jobid=%u\n", jcr->MigrateJobId);
497       edit_uint64(jcr->MigrateJobId, ids.list);
498       ids.count = 1;
499    } else {
500       switch (jcr->job->selection_type) {
501       case MT_JOB:
502          if (!regex_find_jobids(jcr, &ids, sql_job, sql_jobids_from_job, "Job")) {
503             goto bail_out;
504          } 
505          break;
506       case MT_CLIENT:
507          if (!regex_find_jobids(jcr, &ids, sql_client, sql_jobids_from_client, "Client")) {
508             goto bail_out;
509          } 
510          break;
511       case MT_VOLUME:
512          if (!regex_find_jobids(jcr, &ids, sql_vol, sql_jobids_from_vol, "Volume")) {
513             goto bail_out;
514          } 
515          break;
516       case MT_SQLQUERY:
517          if (!jcr->job->selection_pattern) {
518             Jmsg(jcr, M_FATAL, 0, _("No Migration SQL selection pattern specified.\n"));
519             goto bail_out;
520          }
521          Dmsg1(dbglevel, "SQL=%s\n", jcr->job->selection_pattern);
522          if (!db_sql_query(jcr->db, jcr->job->selection_pattern,
523               dbid_handler, (void *)&ids)) {
524             Jmsg(jcr, M_FATAL, 0,
525                  _("SQL failed. ERR=%s\n"), db_strerror(jcr->db));
526             goto bail_out;
527          }
528          break;
529       case MT_SMALLEST_VOL:
530          if (!find_mediaid_then_jobids(jcr, &ids, sql_smallest_vol, "Smallest Volume")) {
531             goto bail_out;
532          }
533          break;
534       case MT_OLDEST_VOL:
535          if (!find_mediaid_then_jobids(jcr, &ids, sql_oldest_vol, "Oldest Volume")) {
536             goto bail_out;
537          }
538          break;
539
540       case MT_POOL_OCCUPANCY:
541          ctx.count = 0;
542          /* Find count of bytes in pool */
543          Mmsg(query, sql_pool_bytes, jcr->pool->hdr.name);
544          if (!db_sql_query(jcr->db, query.c_str(), db_int64_handler, (void *)&ctx)) {
545             Jmsg(jcr, M_FATAL, 0, _("SQL failed. ERR=%s\n"), db_strerror(jcr->db));
546             goto bail_out;
547          }
548          if (ctx.count == 0) {
549             Jmsg(jcr, M_INFO, 0, _("No Volumes found to migrate.\n"));
550             goto ok_out;
551          }
552          pool_bytes = ctx.value;
553          Dmsg2(dbglevel, "highbytes=%d pool=%d\n", (int)jcr->pool->MigrationHighBytes,
554                (int)pool_bytes);
555          if (pool_bytes < (int64_t)jcr->pool->MigrationHighBytes) {
556             Jmsg(jcr, M_INFO, 0, _("No Volumes found to migrate.\n"));
557             goto ok_out;
558          }
559          Dmsg0(dbglevel, "We should do Occupation migration.\n");
560
561          ids.count = 0;
562          /* Find a list of MediaIds that could be migrated */
563          Mmsg(query, sql_mediaids, jcr->pool->hdr.name);
564 //       Dmsg1(dbglevel, "query=%s\n", query.c_str());
565          if (!db_sql_query(jcr->db, query.c_str(), dbid_handler, (void *)&ids)) {
566             Jmsg(jcr, M_FATAL, 0, _("SQL failed. ERR=%s\n"), db_strerror(jcr->db));
567             goto bail_out;
568          }
569          if (ids.count == 0) {
570             Jmsg(jcr, M_INFO, 0, _("No Volumes found to migrate.\n"));
571             goto ok_out;
572          }
573          Dmsg2(dbglevel, "Pool Occupancy ids=%d MediaIds=%s\n", ids.count, ids.list);
574
575          /*
576           * Now loop over MediaIds getting more JobIds to migrate until
577           *  we reduce the pool occupancy below the low water mark.
578           */
579          p = ids.list;
580          for (int i=0; i < (int)ids.count; i++) {
581             stat = get_next_dbid_from_list(&p, &MediaId);
582             Dmsg2(dbglevel, "get_next_dbid stat=%d MediaId=%u\n", stat, MediaId);
583             if (stat < 0) {
584                Jmsg(jcr, M_FATAL, 0, _("Invalid MediaId found.\n"));
585                goto bail_out;
586             } else if (stat == 0) {
587                break;
588             }
589             mid.count = 1;
590             Mmsg(mid.list, "%s", edit_int64(MediaId, ed1));
591             ok = find_jobids_from_mediaid_list(jcr, &mid, "Volumes");
592             if (!ok) {
593                continue;
594             }
595             if (i != 0) {
596                pm_strcat(jids.list, ",");
597             }
598             pm_strcat(jids.list, mid.list);
599             jids.count += mid.count;
600
601             /* Now get the count of bytes added */
602             ctx.count = 0;
603             /* Find count of bytes from Jobs */
604             Mmsg(query, sql_job_bytes, mid.list);
605             if (!db_sql_query(jcr->db, query.c_str(), db_int64_handler, (void *)&ctx)) {
606                Jmsg(jcr, M_FATAL, 0, _("SQL failed. ERR=%s\n"), db_strerror(jcr->db));
607                goto bail_out;
608             }
609             pool_bytes -= ctx.value;
610             Dmsg1(dbglevel, "Job bytes=%d\n", (int)ctx.value);
611             Dmsg2(dbglevel, "lowbytes=%d pool=%d\n", (int)jcr->pool->MigrationLowBytes,
612                   (int)pool_bytes);
613             if (pool_bytes <= (int64_t)jcr->pool->MigrationLowBytes) {
614                Dmsg0(dbglevel, "We should be done.\n");
615                break;
616             }
617
618          }
619          Dmsg2(dbglevel, "Pool Occupancy ids=%d JobIds=%s\n", jids.count, jids.list);
620
621          break;
622
623       case MT_POOL_TIME:
624          ttime = time(NULL) - (time_t)jcr->pool->MigrationTime;
625          (void)localtime_r(&ttime, &tm);
626          strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
627
628          ids.count = 0;
629          Mmsg(query, sql_pool_time, jcr->pool->hdr.name, dt);
630 //       Dmsg1(000, "query=%s\n", query.c_str());
631          if (!db_sql_query(jcr->db, query.c_str(), dbid_handler, (void *)&ids)) {
632             Jmsg(jcr, M_FATAL, 0, _("SQL failed. ERR=%s\n"), db_strerror(jcr->db));
633             goto bail_out;
634          }
635          if (ids.count == 0) {
636             Jmsg(jcr, M_INFO, 0, _("No Volumes found to migrate.\n"));
637             goto ok_out;
638          }
639          Dmsg2(dbglevel, "PoolTime ids=%d JobIds=%s\n", ids.count, ids.list);
640          break;
641
642       default:
643          Jmsg(jcr, M_FATAL, 0, _("Unknown Migration Selection Type.\n"));
644          goto bail_out;
645       }
646    }
647
648    /*
649     * Loop over all jobids except the last one, sending
650     *  them to start_migration_job(), which will start a job
651     *  for each of them.  For the last JobId, we handle it below.
652     */
653    p = ids.list;
654    for (int i=1; i < (int)ids.count; i++) {
655       JobId = 0;
656       stat = get_next_jobid_from_list(&p, &JobId);
657       Dmsg2(dbglevel, "get_next_jobid stat=%d JobId=%u\n", stat, JobId);
658       jcr->MigrateJobId = JobId;
659       start_migration_job(jcr);
660       if (stat < 0) {
661          Jmsg(jcr, M_FATAL, 0, _("Invalid JobId found.\n"));
662          goto bail_out;
663       } else if (stat == 0) {
664          Jmsg(jcr, M_INFO, 0, _("No JobIds found to migrate.\n"));
665          goto ok_out;
666       }
667    }
668    
669    /* Now get the last JobId and handle it in the current job */
670    JobId = 0;
671    stat = get_next_jobid_from_list(&p, &JobId);
672    Dmsg2(dbglevel, "Last get_next_jobid stat=%d JobId=%u\n", stat, JobId);
673    if (stat < 0) {
674       Jmsg(jcr, M_FATAL, 0, _("Invalid JobId found.\n"));
675       goto bail_out;
676    } else if (stat == 0) {
677       Jmsg(jcr, M_INFO, 0, _("No JobIds found to migrate.\n"));
678       goto ok_out;
679    }
680
681    jcr->previous_jr.JobId = JobId;
682    Dmsg1(100, "Previous jobid=%d\n", jcr->previous_jr.JobId);
683
684    if (!db_get_job_record(jcr, jcr->db, &jcr->previous_jr)) {
685       Jmsg(jcr, M_FATAL, 0, _("Could not get job record for JobId %s to migrate. ERR=%s"),
686            edit_int64(jcr->previous_jr.JobId, ed1),
687            db_strerror(jcr->db));
688       goto bail_out;
689    }
690    Jmsg(jcr, M_INFO, 0, _("Migration using JobId=%d Job=%s\n"),
691       jcr->previous_jr.JobId, jcr->previous_jr.Job);
692
693 ok_out:
694    free_pool_memory(ids.list);
695    free_pool_memory(mid.list);
696    free_pool_memory(jids.list);
697    return true;
698
699 bail_out:
700    free_pool_memory(ids.list);
701    free_pool_memory(mid.list);
702    free_pool_memory(jids.list);
703    return false;
704 }
705
706 static void start_migration_job(JCR *jcr)
707 {
708    UAContext *ua = new_ua_context(jcr);
709    char ed1[50];
710    ua->batch = true;
711    Mmsg(ua->cmd, "run %s jobid=%s", jcr->job->hdr.name, 
712         edit_uint64(jcr->MigrateJobId, ed1));
713    Dmsg1(dbglevel, "=============== Migration cmd=%s\n", ua->cmd);
714    parse_ua_args(ua);                 /* parse command */
715    int stat = run_cmd(ua, ua->cmd);
716    if (stat == 0) {
717       Jmsg(jcr, M_ERROR, 0, _("Could not start migration job.\n"));
718    } else {
719       Jmsg(jcr, M_INFO, 0, _("Migration JobId %d started.\n"), stat);
720    }
721    free_ua_context(ua);
722 }
723
724 static bool find_mediaid_then_jobids(JCR *jcr, idpkt *ids, const char *query1,
725                  const char *type) 
726 {
727    bool ok = false;
728    POOL_MEM query(PM_MESSAGE);
729
730    ids->count = 0;
731    /* Basic query for MediaId */
732    Mmsg(query, query1, jcr->pool->hdr.name);
733    if (!db_sql_query(jcr->db, query.c_str(), dbid_handler, (void *)ids)) {
734       Jmsg(jcr, M_FATAL, 0, _("SQL failed. ERR=%s\n"), db_strerror(jcr->db));
735       goto bail_out;
736    }
737    if (ids->count == 0) {
738       Jmsg(jcr, M_INFO, 0, _("No %ss found to migrate.\n"), type);
739    }
740    if (ids->count != 1) {
741       Jmsg(jcr, M_FATAL, 0, _("SQL logic error. Count should be 1 but is %d\n"), 
742          ids->count);
743       goto bail_out;
744    }
745    Dmsg1(dbglevel, "Smallest Vol Jobids=%s\n", ids->list);
746
747    ok = find_jobids_from_mediaid_list(jcr, ids, type);
748
749 bail_out:
750    return ok;
751 }
752
753 static bool find_jobids_from_mediaid_list(JCR *jcr, idpkt *ids, const char *type) 
754 {
755    bool ok = false;
756    POOL_MEM query(PM_MESSAGE);
757
758    Mmsg(query, sql_jobids_from_mediaid, ids->list);
759    ids->count = 0;
760    if (!db_sql_query(jcr->db, query.c_str(), dbid_handler, (void *)ids)) {
761       Jmsg(jcr, M_FATAL, 0, _("SQL failed. ERR=%s\n"), db_strerror(jcr->db));
762       goto bail_out;
763    }
764    if (ids->count == 0) {
765       Jmsg(jcr, M_INFO, 0, _("No %ss found to migrate.\n"), type);
766    }
767    ok = true;
768 bail_out:
769    return ok;
770 }
771
772 static bool regex_find_jobids(JCR *jcr, idpkt *ids, const char *query1,
773                  const char *query2, const char *type) 
774 {
775    dlist *item_chain;
776    uitem *item = NULL;
777    uitem *last_item = NULL;
778    regex_t preg;
779    char prbuf[500];
780    int rc;
781    bool ok = false;
782    POOL_MEM query(PM_MESSAGE);
783
784    item_chain = New(dlist(item, &item->link));
785    if (!jcr->job->selection_pattern) {
786       Jmsg(jcr, M_FATAL, 0, _("No Migration %s selection pattern specified.\n"),
787          type);
788       goto bail_out;
789    }
790    Dmsg1(dbglevel, "regex=%s\n", jcr->job->selection_pattern);
791    /* Compile regex expression */
792    rc = regcomp(&preg, jcr->job->selection_pattern, REG_EXTENDED);
793    if (rc != 0) {
794       regerror(rc, &preg, prbuf, sizeof(prbuf));
795       Jmsg(jcr, M_FATAL, 0, _("Could not compile regex pattern \"%s\" ERR=%s\n"),
796            jcr->job->selection_pattern, prbuf);
797       goto bail_out;
798    }
799    /* Basic query for names */
800    Mmsg(query, query1, jcr->pool->hdr.name);
801    Dmsg1(dbglevel, "query1=%s\n", query.c_str());
802    if (!db_sql_query(jcr->db, query.c_str(), unique_name_handler, 
803         (void *)item_chain)) {
804       Jmsg(jcr, M_FATAL, 0,
805            _("SQL to get %s failed. ERR=%s\n"), type, db_strerror(jcr->db));
806       goto bail_out;
807    }
808    /* Now apply the regex to the names and remove any item not matched */
809    foreach_dlist(item, item_chain) {
810       const int nmatch = 30;
811       regmatch_t pmatch[nmatch];
812       if (last_item) {
813          Dmsg1(dbglevel, "Remove item %s\n", last_item->item);
814          free(last_item->item);
815          item_chain->remove(last_item);
816       }
817       Dmsg1(dbglevel, "Item=%s\n", item->item);
818       rc = regexec(&preg, item->item, nmatch, pmatch,  0);
819       if (rc == 0) {
820          last_item = NULL;   /* keep this one */
821       } else {   
822          last_item = item;
823       }
824    }
825    if (last_item) {
826       free(last_item->item);
827       Dmsg1(dbglevel, "Remove item %s\n", last_item->item);
828       item_chain->remove(last_item);
829    }
830    regfree(&preg);
831    /* 
832     * At this point, we have a list of items in item_chain
833     *  that have been matched by the regex, so now we need
834     *  to look up their jobids.
835     */
836    ids->count = 0;
837    foreach_dlist(item, item_chain) {
838       Dmsg2(dbglevel, "Got %s: %s\n", type, item->item);
839       Mmsg(query, query2, item->item, jcr->pool->hdr.name);
840       Dmsg1(dbglevel, "query2=%s\n", query.c_str());
841       if (!db_sql_query(jcr->db, query.c_str(), dbid_handler, (void *)ids)) {
842          Jmsg(jcr, M_FATAL, 0,
843               _("SQL failed. ERR=%s\n"), db_strerror(jcr->db));
844          goto bail_out;
845       }
846    }
847    if (ids->count == 0) {
848       Jmsg(jcr, M_INFO, 0, _("No %ss found to migrate.\n"), type);
849    }
850    ok = true;
851 bail_out:
852    Dmsg2(dbglevel, "Count=%d Jobids=%s\n", ids->count, ids->list);
853    delete item_chain;
854    Dmsg0(dbglevel, "After delete item_chain\n");
855    return ok;
856 }
857
858
859 /*
860  * Release resources allocated during backup.
861  */
862 void migration_cleanup(JCR *jcr, int TermCode)
863 {
864    char sdt[MAX_TIME_LENGTH], edt[MAX_TIME_LENGTH];
865    char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], elapsed[50];
866    char ec6[50], ec7[50], ec8[50];
867    char term_code[100], sd_term_msg[100];
868    const char *term_msg;
869    int msg_type;
870    MEDIA_DBR mr;
871    double kbps;
872    utime_t RunTime;
873    JCR *mig_jcr = jcr->mig_jcr;
874    POOL_MEM query(PM_MESSAGE);
875
876    Dmsg2(100, "Enter migrate_cleanup %d %c\n", TermCode, TermCode);
877    dequeue_messages(jcr);             /* display any queued messages */
878    memset(&mr, 0, sizeof(mr));
879    set_jcr_job_status(jcr, TermCode);
880    update_job_end_record(jcr);        /* update database */
881
882    /* 
883     * Check if we actually did something.  
884     *  mig_jcr is jcr of the newly migrated job.
885     */
886    if (mig_jcr) {
887       mig_jcr->JobFiles = jcr->JobFiles = jcr->SDJobFiles;
888       mig_jcr->JobBytes = jcr->JobBytes = jcr->SDJobBytes;
889       mig_jcr->VolSessionId = jcr->VolSessionId;
890       mig_jcr->VolSessionTime = jcr->VolSessionTime;
891       mig_jcr->jr.RealEndTime = 0; 
892       mig_jcr->jr.PriorJobId = jcr->previous_jr.JobId;
893
894       set_jcr_job_status(mig_jcr, TermCode);
895
896   
897       update_job_end_record(mig_jcr);
898      
899       /* Update final items to set them to the previous job's values */
900       Mmsg(query, "UPDATE Job SET StartTime='%s',EndTime='%s',"
901                   "JobTDate=%s WHERE JobId=%s", 
902          jcr->previous_jr.cStartTime, jcr->previous_jr.cEndTime, 
903          edit_uint64(jcr->previous_jr.JobTDate, ec1),
904          edit_uint64(mig_jcr->jr.JobId, ec2));
905       db_sql_query(mig_jcr->db, query.c_str(), NULL, NULL);
906
907       /* Now marke the previous job as migrated */
908       Mmsg(query, "UPDATE Job SET Type='%c' WHERE JobId=%s",
909            (char)JT_MIGRATED_JOB, edit_uint64(jcr->previous_jr.JobId, ec1));
910       db_sql_query(mig_jcr->db, query.c_str(), NULL, NULL);
911
912       if (!db_get_job_record(jcr, jcr->db, &jcr->jr)) {
913          Jmsg(jcr, M_WARNING, 0, _("Error getting job record for stats: %s"),
914             db_strerror(jcr->db));
915          set_jcr_job_status(jcr, JS_ErrorTerminated);
916       }
917
918       bstrncpy(mr.VolumeName, jcr->VolumeName, sizeof(mr.VolumeName));
919       if (!db_get_media_record(jcr, jcr->db, &mr)) {
920          Jmsg(jcr, M_WARNING, 0, _("Error getting Media record for Volume \"%s\": ERR=%s"),
921             mr.VolumeName, db_strerror(jcr->db));
922          set_jcr_job_status(jcr, JS_ErrorTerminated);
923       }
924
925       update_bootstrap_file(mig_jcr);
926
927       if (!db_get_job_volume_names(mig_jcr, mig_jcr->db, mig_jcr->jr.JobId, &mig_jcr->VolumeName)) {
928          /*
929           * Note, if the job has erred, most likely it did not write any
930           *  tape, so suppress this "error" message since in that case
931           *  it is normal.  Or look at it the other way, only for a
932           *  normal exit should we complain about this error.
933           */
934          if (jcr->JobStatus == JS_Terminated && jcr->jr.JobBytes) {
935             Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(mig_jcr->db));
936          }
937          mig_jcr->VolumeName[0] = 0;         /* none */
938       }
939   }
940
941    msg_type = M_INFO;                 /* by default INFO message */
942    switch (jcr->JobStatus) {
943    case JS_Terminated:
944       if (jcr->Errors || jcr->SDErrors) {
945          term_msg = _("%s OK -- with warnings");
946       } else {
947          term_msg = _("%s OK");
948       }
949       break;
950    case JS_FatalError:
951    case JS_ErrorTerminated:
952       term_msg = _("*** %s Error ***");
953       msg_type = M_ERROR;          /* Generate error message */
954       if (jcr->store_bsock) {
955          bnet_sig(jcr->store_bsock, BNET_TERMINATE);
956          if (jcr->SD_msg_chan) {
957             pthread_cancel(jcr->SD_msg_chan);
958          }
959       }
960       break;
961    case JS_Canceled:
962       term_msg = _("%s Canceled");
963       if (jcr->store_bsock) {
964          bnet_sig(jcr->store_bsock, BNET_TERMINATE);
965          if (jcr->SD_msg_chan) {
966             pthread_cancel(jcr->SD_msg_chan);
967          }
968       }
969       break;
970    default:
971       term_msg = _("Inappropriate %s term code");
972       break;
973    }
974    bsnprintf(term_code, sizeof(term_code), term_msg, "Migration");
975    bstrftimes(sdt, sizeof(sdt), jcr->jr.StartTime);
976    bstrftimes(edt, sizeof(edt), jcr->jr.EndTime);
977    RunTime = jcr->jr.EndTime - jcr->jr.StartTime;
978    if (RunTime <= 0) {
979       kbps = 0;
980    } else {
981       kbps = (double)jcr->SDJobBytes / (1000 * RunTime);
982    }
983
984
985    jobstatus_to_ascii(jcr->SDJobStatus, sd_term_msg, sizeof(sd_term_msg));
986
987    Jmsg(jcr, msg_type, 0, _("Bacula %s (%s): %s\n"
988 "  Prev Backup JobId:      %s\n"
989 "  New Backup JobId:       %s\n"
990 "  Migration JobId:        %s\n"
991 "  Migration Job:          %s\n"
992 "  Backup Level:           %s%s\n"
993 "  Client:                 %s\n"
994 "  FileSet:                \"%s\" %s\n"
995 "  Pool:                   \"%s\" (From %s)\n"
996 "  Storage:                \"%s\" (From %s)\n"
997 "  Start time:             %s\n"
998 "  End time:               %s\n"
999 "  Elapsed time:           %s\n"
1000 "  Priority:               %d\n"
1001 "  SD Files Written:       %s\n"
1002 "  SD Bytes Written:       %s (%sB)\n"
1003 "  Rate:                   %.1f KB/s\n"
1004 "  Volume name(s):         %s\n"
1005 "  Volume Session Id:      %d\n"
1006 "  Volume Session Time:    %d\n"
1007 "  Last Volume Bytes:      %s (%sB)\n"
1008 "  SD Errors:              %d\n"
1009 "  SD termination status:  %s\n"
1010 "  Termination:            %s\n\n"),
1011    VERSION,
1012    LSMDATE,
1013         edt, 
1014         mig_jcr ? edit_uint64(jcr->previous_jr.JobId, ec6) : "0", 
1015         mig_jcr ? edit_uint64(mig_jcr->jr.JobId, ec7) : "0",
1016         edit_uint64(jcr->jr.JobId, ec8),
1017         jcr->jr.Job,
1018         level_to_str(jcr->JobLevel), jcr->since,
1019         jcr->client->name(),
1020         jcr->fileset->name(), jcr->FSCreateTime,
1021         jcr->pool->name(), jcr->pool_source,
1022         jcr->wstore->name(), jcr->storage_source,
1023         sdt,
1024         edt,
1025         edit_utime(RunTime, elapsed, sizeof(elapsed)),
1026         jcr->JobPriority,
1027         edit_uint64_with_commas(jcr->SDJobFiles, ec1),
1028         edit_uint64_with_commas(jcr->SDJobBytes, ec2),
1029         edit_uint64_with_suffix(jcr->SDJobBytes, ec3),
1030         (float)kbps,
1031         mig_jcr ? mig_jcr->VolumeName : "",
1032         jcr->VolSessionId,
1033         jcr->VolSessionTime,
1034         edit_uint64_with_commas(mr.VolBytes, ec4),
1035         edit_uint64_with_suffix(mr.VolBytes, ec5),
1036         jcr->SDErrors,
1037         sd_term_msg,
1038         term_code);
1039
1040    Dmsg1(100, "migrate_cleanup() mig_jcr=0x%x\n", jcr->mig_jcr);
1041    if (jcr->mig_jcr) {
1042       free_jcr(jcr->mig_jcr);
1043       jcr->mig_jcr = NULL;
1044    }
1045    Dmsg0(100, "Leave migrate_cleanup()\n");
1046 }
1047
1048 /* 
1049  * Return next DBId from comma separated list   
1050  *
1051  * Returns:
1052  *   1 if next DBId returned
1053  *   0 if no more DBIds are in list
1054  *  -1 there is an error
1055  */
1056 static int get_next_dbid_from_list(char **p, DBId_t *DBId)
1057 {
1058    char id[30];
1059    char *q = *p;
1060
1061    id[0] = 0;
1062    for (int i=0; i<(int)sizeof(id); i++) {
1063       if (*q == 0) {
1064          break;
1065       } else if (*q == ',') {
1066          q++;
1067          break;
1068       }
1069       id[i] = *q++;
1070       id[i+1] = 0;
1071    }
1072    if (id[0] == 0) {
1073       return 0;
1074    } else if (!is_a_number(id)) {
1075       return -1;                      /* error */
1076    }
1077    *p = q;
1078    *DBId = str_to_int64(id);
1079    return 1;
1080 }