+2003-07-xx Version 1.31 Beta 28Jul03
+- Add sleep(1) to console when it gets a SIGTSTP signal
+ to prevent it from using 100% of the CPU.
+- Improve description of Priorities.
+- Add a bit more documentation to jobq.c
+- Complete hash table routine htable.c htable.h
+- Change M_INFO to M_ERROR in attribs.c for Windows errors.
+
2003-07-23 Version 1.31 Beta 22Jul03
- Apply a patch from Nic Bellamy that clarifies the error messages
during recycling volumes.
Kern's ToDo List
- 14 July 2003
+ 28 July 2003
Documentation to do: (any release a little bit at a time)
- Document running a test version.
(./create_mys... ./make_my...).
- Document all the status codes JobLevel, JobType, JobStatus.
- Document dynamic DNS
+- On Fri, 2003-07-25 at 22:39, Thiago Lima wrote:
+ I've just noticed that bacula uses the server time to scan the
+ > clients for new files since the last backup in incremental backup.
+ > So if server and client clocks aren't synced you may not backup all
+ > files.
+ >
+ > Example :
+ >
+ > Server time : 16:05
+ > Client time : 16:00
+ > runs full backup
+ >
+ > Server time : 16:15
+ > Client time : 16:10
+ > runs incremental backup
+ >
+ > If there's any file created/changed between 16:00 and 16:05 (client
+ > clock) they will never be backuped.
+ > The solution is keep all your machines clocks synced.
+ >
+ > Is that right? Does anybody have any comments on that? Maybe this
+ > could go to the FAQ?
+ >
+ >
Testing to do: (painful)
- that ALL console command line options work and are always implemented
For 1.31 release:
+
For 1.32:
- Maybe remove multiple simultaneous devices code in SD.
- On Windows with very long path names, it may be impossible to create
(Phil's problem).
- Increment DB version prior to releasing.
- Turn off FULL_DEBUG prior to releasing.
-
fd_set fdset;
struct timeval tv;
- FD_ZERO(&fdset);
- FD_SET(fd, &fdset);
tv.tv_sec = sec;
tv.tv_usec = 0;
for ( ;; ) {
+ FD_ZERO(&fdset);
+ FD_SET(fd, &fdset);
switch(select(fd + 1, &fdset, NULL, NULL, &tv)) {
- case 0: /* timeout */
- return 0;
- case -1:
- if (errno == EINTR || errno == EAGAIN) {
- continue;
- }
- return -1; /* error return */
- default:
- return 1;
+ case 0: /* timeout */
+ return 0;
+ case -1:
+ if (errno == EINTR || errno == EAGAIN) {
+ continue;
+ }
+ return -1; /* error return */
+ default:
+ return 1;
}
}
}
}
again:
switch (wait_for_data(fileno(input), sec)) {
- case 0:
- return 0; /* timeout */
- case -1:
- return -1; /* error */
- default:
- len = sizeof_pool_memory(sock->msg) - 1;
- if (stop) {
- goto again;
- }
- if (fgets(sock->msg, len, input) == NULL) {
- return -1;
- }
- break;
+ case 0:
+ return 0; /* timeout */
+ case -1:
+ return -1; /* error */
+ default:
+ len = sizeof_pool_memory(sock->msg) - 1;
+ if (stop) {
+ sleep(1);
+ goto again;
+ }
+ if (fgets(sock->msg, len, input) == NULL) {
+ return -1;
+ }
+ break;
}
strip_trailing_junk(sock->msg);
sock->msglen = strlen(sock->msg);
};
/*
- * Wait until schedule time arrives before starting
+ * Wait until schedule time arrives before starting. Normally
+ * this routine is only used for jobs started from the console
+ * for which the user explicitly specified a start time. Otherwise
+ * most jobs are put into the job queue only when their
+ * scheduled time arives.
*/
static void *sched_wait(void *arg)
{
}
}
+ /* Ensure that at least one server looks at the queue. */
stat = start_server(jq);
if (stat == 0) {
}
/*
- * Remove a job from the job queue
+ * Remove a job from the job queue. Used only by cancel Console command.
* jq is a queue that was created with jobq_init
* work_item is an element of work
*
/*
- * Start the server thread
+ * Start the server thread if it isn't already running
*/
static int start_server(jobq_t *jq)
{
jobq_add(jq, jcr); /* queue the job to run again */
P(jq->mutex);
free(je); /* free the job entry */
- continue;
+ continue; /* look for another job to run */
}
/*
* Something was actually backed up, so we cannot reuse
njcr->messages = jcr->messages;
Dmsg0(100, "Call to run new job\n");
V(jq->mutex);
- run_job(njcr);
+ run_job(njcr); /* This creates a "new" job */
P(jq->mutex);
Dmsg0(100, "Back from running new job.\n");
}
Dmsg1(100, "Set Job pri=%d\n", Priority);
}
/*
- * Acquire locks
+ * Walk down the list of waiting jobs and attempt
+ * to acquire the resources it needs.
*/
for ( ; je; ) {
+ /* je is current job item on the queue, jn is the next one */
JCR *jcr = je->jcr;
jobq_item_t *jn = (jobq_item_t *)jq->waiting_jobs->next(je);
Dmsg3(100, "Examining Job=%d JobPri=%d want Pri=%d\n",
je = jn;
continue;
}
+ /* Got all locks, now remove it from wait queue and append it
+ * to the ready queue
+ */
jcr->acquired_resource_locks = true;
jq->waiting_jobs->remove(je);
jq->ready_jobs->append(je);
ULARGE_INTEGER li;
POOLMEM *win32_ofile;
+ if (!p_GetFileAttributesEx) {
+ return 0;
+ }
+
if (!p || !*p) { /* we should have attributes */
Dmsg2(100, "Attributes missing. of=%s ofd=%d\n", attr->ofname, ofd->fid);
if (is_bopen(ofd)) {
NULL);
Dmsg3(100, "Error in %s on file %s: ERR=%s\n", prefix, win32_ofile, msg);
strip_trailing_junk(msg);
- Jmsg(jcr, M_INFO, 0, _("Error in %s file %s: ERR=%s\n"), prefix, win32_ofile, msg);
+ Jmsg(jcr, M_ERROR, 0, _("Error in %s file %s: ERR=%s\n"), prefix, win32_ofile, msg);
LocalFree(msg);
}
NULL);
strip_trailing_junk(msg);
if (jcr) {
- Jmsg2(jcr, M_INFO, 0, _("Error in %s: ERR=%s\n"), prefix, msg);
+ Jmsg2(jcr, M_ERROR, 0, _("Error in %s: ERR=%s\n"), prefix, msg);
} else {
MessageBox(NULL, msg, prefix, MB_OK);
}
* htable is a hash table of items (pointers). This code is
* adapted and enhanced from code I wrote in 1982 for a
* relocatable linker. At that time, the hash table size
- * was fixed and a primary number, which essentially providing
- * the hashing. In this program, the hash table can grow when
- * it gets too full, so the table is a binary number. The
+ * was fixed and a primary number, which essentially provides
+ * the randomness. In this program, the hash table can grow when
+ * it gets too full, so the table size here is a binary number. The
* hashing is provided using an idea from Tcl where the initial
- * hash code is then "randomized" a simple calculation from
+ * hash code is then "randomized" using a simple calculation from
* a random number generator that multiplies by a big number
+ * (I multiply by a prime number, while Tcl did not)
* then shifts the results down and does the binary division
- * by masking. Increasing the size of the hash table is simple
- * simply create a new larger table, walk the old table and
- * insert each entry into the new table.
+ * by masking. Increasing the size of the hash table is simple.
+ * Just create a new larger table, walk the old table and
+ * re-hash insert each entry into the new table.
*
*
* Kern Sibbald, July MMIII
return;
}
-htable::htable(void *item, void *link)
+htable::htable(void *item, void *link, int tsize)
{
- init(item, link);
+ init(item, link, tsize);
}
-void htable::init(void *item, void *link)
+void htable::init(void *item, void *link, int tsize)
{
+ int pwr;
+ tsize >>= 2;
+ for (pwr=0; tsize; pwr++) {
+ tsize >>= 1;
+ }
loffset = (char *)link - (char *)item;
- mask = 7; /* 3 bits => table size = 8 */
- rshift = 27; /* start using bits 28, 29, 30 */
+ mask = ~((~0)<<pwr); /* 3 bits => table size = 8 */
+ rshift = 30 - pwr; /* start using bits 28, 29, 30 */
num_items = 0; /* number of entries in table */
- buckets = 8; /* hash table size -- power of two */
+ buckets = 1<<pwr; /* hash table size -- power of two */
max_items = buckets * 4; /* allow average 4 entries per chain */
table = (hlink **)malloc(buckets * sizeof(hlink *));
memset(table, 0, buckets * sizeof(hlink *));
walk_index = 0;
}
+void * htable::operator new(size_t)
+{
+ return malloc(sizeof(htable));
+}
+
+void htable::operator delete(void *tbl)
+{
+ ((htable *)tbl)->destroy();
+ free(tbl);
+}
+
+uint32_t htable::size()
+{
+ return num_items;
+}
+
+void htable::stats()
+{
+ int count[10];
+ int max = 0;
+ int i, j;
+ hlink *p;
+ printf("\n\nNumItems=%d\nBuckets=%d\n", num_items, buckets);
+ for (i=0; i<10; i++) {
+ count[i] = 0;
+ }
+ for (i=0; i<(int)buckets; i++) {
+ p = table[i];
+ j = 0;
+ while (p) {
+ p = (hlink *)(p->next);
+ j++;
+ }
+ if (j > max) {
+ max = j;
+ }
+ if (j < 10) {
+ count[j]++;
+ }
+ }
+ for (i=0; i<10; i++) {
+ printf("%2d: %d\n",i, count[i]);
+ }
+ printf("max = %d\n", max);
+}
+
void htable::grow_table()
{
Dmsg1(000, "Grow called old size = %d\n", buckets);
MYJCR *save_jcr = NULL, *item;
MYJCR *jcr = NULL;
int count = 0;
-
+
jcrtbl = (htable *)malloc(sizeof(htable));
- jcrtbl->init(jcr, &jcr->link);
+ jcrtbl->init(jcr, &jcr->link, NITEMS);
- Dmsg0(000, "Insert NITEMS items 0-19\n");
+ Dmsg1(000, "Inserting %d items\n", NITEMS);
for (int i=0; i<NITEMS; i++) {
sprintf(mkey, "This is htable item %d", i);
jcr = (MYJCR *)malloc(sizeof(MYJCR));
printf("Item 10's key is: %s\n", item->key);
}
+ jcrtbl->stats();
printf("Walk the hash table:\n");
for (MYJCR *jcr=(MYJCR *)jcrtbl->first(); jcr; jcr=(MYJCR *)jcrtbl->next() ) {
- printf("htable item = %s\n", jcr->key);
+// printf("htable item = %s\n", jcr->key);
free(jcr->key);
count++;
}
*
*/
-#define OFFSET(item,link) ((char *)link - (char *)item)
-
struct hlink {
- void *next; /* next hash item */
- char *key; /* key this item */
- uint32_t hash; /* hash for this key */
+ void *next; /* next hash item */
+ char *key; /* key this item */
+ uint32_t hash; /* hash for this key */
};
class htable {
- hlink **table; /* hash table */
- int loffset; /* link offset in item */
- uint32_t num_items; /* current number of items */
- uint32_t max_items; /* maximum items before growing */
- uint32_t buckets; /* size of hash table */
- uint32_t hash; /* temp storage */
- uint32_t index; /* temp storage */
+ hlink **table; /* hash table */
+ int loffset; /* link offset in item */
+ uint32_t num_items; /* current number of items */
+ uint32_t max_items; /* maximum items before growing */
+ uint32_t buckets; /* size of hash table */
+ uint32_t hash; /* temp storage */
+ uint32_t index; /* temp storage */
uint32_t mask; /* "remainder" mask */
- uint32_t rshift; /* amount to shift down */
- hlink *walkptr; /* table walk pointer */
- uint32_t walk_index; /* table walk index */
- void hash_index(char *key); /* produce hash key,index */
- void grow_table(); /* grow the table */
+ uint32_t rshift; /* amount to shift down */
+ hlink *walkptr; /* table walk pointer */
+ uint32_t walk_index; /* table walk index */
+ void hash_index(char *key); /* produce hash key,index */
+ void grow_table(); /* grow the table */
public:
- htable(void *item, void *link);
- void init(void *item, void *link);
+ htable(void *item, void *link, int tsize = 31);
+ void init(void *item, void *link, int tsize = 31);
bool insert(char *key, void *item);
void *lookup(char *key);
- void *first(); /* get first item in table */
- void *next(); /* get next item in table */
+ void *first(); /* get first item in table */
+ void *next(); /* get next item in table */
void destroy();
+ void stats(); /* print stats about the table */
+ uint32_t size(); /* return size of table */
void * operator new(size_t);
void operator delete(void *);
};
/* */
#define VERSION "1.31"
#define VSTRING "1"
-#define BDATE "22 Jul 2003"
-#define LSMDATE "22Jul03"
+#define BDATE "28 Jul 2003"
+#define LSMDATE "28Jul03"
/* Debug flags */
#define DEBUG 1