Commit 3c78551c authored by Per Cederqvist's avatar Per Cederqvist
Browse files

(remove_loc_no): New static function.

(read_ranges_precondition): New static function.
(read_ranges_postcondition): New static function.
(mark_as_read): Extracted debug code to read_ranges_precondition
	and read_ranges_postcondition.
(mark_as_unread): New function.
(check_range_list): New static function.
(set_read_ranges): New function.
parent f923fdc1
/*
* $Id: membership.c,v 0.79 2002/11/13 00:41:15 ceder Exp $
* $Id: membership.c,v 0.80 2002/11/15 17:15:12 ceder Exp $
* Copyright (C) 1991-2002 Lysator Academic Computer Association.
*
* This file is part of the LysKOM server.
......@@ -553,8 +553,7 @@ adjust_read(Membership *m,
}
/*
* insert TEXT in the list of read texts in M. The texts are sorted.
* m->no_of_read is updated.
* insert TEXT in the set of read texts in M.
*
* Returns FAILURE if the text is already read.
*
......@@ -632,6 +631,90 @@ insert_loc_no(Local_text_no text,
return OK;
}
static void
remove_loc_no(Local_text_no text,
Membership * m)
{
struct read_range *lo;
struct read_range *hi;
struct read_range *mid;
struct read_range *begin;
struct read_range *end;
ptrdiff_t save;
struct read_range *gap;
struct read_range *move;
if (m->no_of_read_ranges == 0)
return;
begin = lo = &m->read_ranges[0];
end = hi = lo + m->no_of_read_ranges;
while (hi - lo > 1)
{
mid = lo + (hi - lo) / 2;
if (text < mid->first_read - 1)
hi = mid;
else if (text > mid->last_read + 1)
lo = mid;
else
{
lo = mid;
hi = mid + 1;
}
}
if (text < lo->first_read || text > lo->last_read)
return; /* This text was already unread. */
if (text == lo->first_read)
{
if (lo->first_read != lo->last_read)
{
/* Remove the first text of this range. */
lo->first_read++;
return;
}
/* This range contains a single text. Remove the entire range. */
for (move = lo; move < (end-1); move++)
*move = *(move+1);
m->no_of_read_ranges--;
return;
}
if (text == lo->last_read)
{
assert(text != lo->first_read);
/* Remove the last text of this range. */
lo->last_read--;
return;
}
assert(lo->first_read < text && text < lo->last_read);
/* We have to split this block. */
save = lo - begin;
m->read_ranges = srealloc(
m->read_ranges,
++(m->no_of_read_ranges) * sizeof(m->read_ranges[0]));
begin = &m->read_ranges[0];
gap = begin + save;
end = begin + m->no_of_read_ranges;
for (move = end - 1; move > gap; move--)
*move = *(move - 1);
assert(gap->first_read == (gap+1)->first_read);
assert(gap->last_read == (gap+1)->last_read);
assert(text > gap->first_read);
assert(text < gap->last_read);
gap->last_read = text - 1;
(gap+1)->first_read = text + 1;
return;
}
/*
* Send a new-membership message to the affected person
......@@ -1319,8 +1402,60 @@ check_membership(Pers_no pno,
return errors;
}
static void
read_ranges_precondition(Membership *m,
Membership *save,
const Conference *conf_c,
const char *func)
{
if (check_membership(ACTPERS, conf_c, m) > 0)
kom_log("%s(): the above error was detected on entry to me.\n", func);
if (m->read_ranges == NULL && m->no_of_read_ranges != 0)
{
kom_log("%s(): m->read_ranges == NULL && "
"m->no_of_read_ranges == %lu (corrected).\n",
func,
(unsigned long)m->no_of_read_ranges);
m->no_of_read_ranges = 0;
}
*save = *m;
save->read_ranges = smalloc(m->no_of_read_ranges
* sizeof(save->read_ranges[0]));
memcpy(save->read_ranges, m->read_ranges,
m->no_of_read_ranges * sizeof(save->read_ranges[0]));
}
static int
read_ranges_postcondition(Membership *m,
Membership *save,
const Conference *conf_c,
const char *func)
{
static int log_no = 0;
int ret = 0;
/* Check that the membership is correct. Otherwise log all info. */
if (check_membership(ACTPERS, conf_c, m) > 0 && log_no < 40)
{
kom_log("%s(): (%d) Person %lu has a corrupt membership:\n",
func, ++log_no, (unsigned long)ACTPERS);
kom_log("Dump of data follows: <original membership>"
"<updated membership>\n");
foutput_membership(stderr, save);
putc('\n', stderr);
foutput_membership(stderr, m);
ret = -1;
}
sfree(save->read_ranges);
return ret;
}
#endif
/*
* mark_as_read() is used to tell LysKOM which texts you have read.
* You can mark several texts in one chunk, but the chunk should not
......@@ -1361,35 +1496,25 @@ mark_as_read (Conf_no conference,
#ifdef DEBUG_MARK_AS_READ
Membership original;
int loop;
static int log_no = 0;
#endif
CHK_CONNECTION(FAILURE);
CHK_LOGIN(FAILURE);
GET_C_STAT(conf_c, conference, FAILURE);
if ( (m = locate_membership( conference, ACT_P)) == NULL)
{
#if 1
err_stat = conference;
kom_errno = KOM_NOT_MEMBER;
#else /* FIXME: (bug 48): Write test case, then do like below. */
set_conf_errno(active_connection, conference, KOM_NOT_MEMBER);
#endif
return FAILURE;
}
#ifdef DEBUG_MARK_AS_READ
if ( m->read_ranges == NULL && m->no_of_read_ranges != 0 )
{
kom_log("mark_as_read(): m->read_ranges == NULL && "
"m->no_of_read_ranges == %lu (corrected).\n",
(unsigned long)m->no_of_read_ranges);
m->no_of_read_ranges = 0;
}
original = *m;
original.read_ranges = smalloc(m->no_of_read_ranges
* sizeof(original.read_ranges[0]));
memcpy(original.read_ranges, m->read_ranges,
m->no_of_read_ranges * sizeof(original.read_ranges[0]));
read_ranges_precondition(m, &original, conf_c, "mark_as_read");
#endif
for( i = no_of_texts; i > 0; i--, text_arr++ )
......@@ -1430,6 +1555,7 @@ mark_as_read (Conf_no conference,
}
adjust_read(m, conf_c);
/* FIXME (bug 877): shouldn't this be mark_person_as_changed? */
mark_conference_as_changed(conference);
if (active_connection->cwc == conference)
......@@ -1437,29 +1563,187 @@ mark_as_read (Conf_no conference,
}
#ifdef DEBUG_MARK_AS_READ
/* Check that the membership is correct. Otherwise log all info. */
if (check_membership(ACTPERS, conf_c, m) > 0 && log_no < 40)
if (read_ranges_postcondition(m, &original, conf_c, "mark_as_read") < 0)
{
kom_log("mark_as_read(): (%d) Person %lu has a corrupt membership:\n",
++log_no, (unsigned long)ACTPERS);
kom_log("Dump of data follows: <original membership>"
"<updated membership> <texts to mark>\n");
foutput_membership(stderr, &original);
putc('\n', stderr);
foutput_membership(stderr, m);
kom_log("this was triggered by an attempt to mark this as read\n");
fprintf(stderr, "\n%lu { ", (unsigned long)no_of_texts);
for ( loop = 0; loop < no_of_texts; loop++ )
{
for (loop = 0; loop < no_of_texts; loop++)
fprintf(stderr, "\n%lu ", (unsigned long)text_arr_start[loop]);
}
fprintf(stderr, "}\n");
}
#endif
return retval;
}
extern Success
mark_as_unread(Conf_no conference,
Local_text_no lno)
{
Membership * m;
Conference * conf_c;
Success retval = OK;
#ifdef DEBUG_MARK_AS_READ
Membership original;
#endif
CHK_CONNECTION(FAILURE);
CHK_LOGIN(FAILURE);
GET_C_STAT(conf_c, conference, FAILURE);
if ((m = locate_membership(conference, ACT_P)) == NULL)
{
set_conf_errno(active_connection, conference, KOM_NOT_MEMBER);
return FAILURE;
}
#ifdef DEBUG_MARK_AS_READ
read_ranges_precondition(m, &original, conf_c, "unmark_as_read");
#endif
if (lno == 0)
{
kom_errno = KOM_LOCAL_TEXT_ZERO;
err_stat = 0;
retval = FAILURE;
}
else if (lno >= l2g_first_appendable_key(&conf_c->texts))
{
kom_errno = KOM_NO_SUCH_LOCAL_TEXT;
err_stat = lno;
retval = FAILURE;
}
else
{
remove_loc_no(lno, m);
adjust_read(m, conf_c);
/* FIXME (bug 877): mark_as_read uses mark_conference_as_changed
instead. If that is proper, then this line is wrong. */
mark_person_as_changed(ACTPERS);
}
#ifdef DEBUG_MARK_AS_READ
if (read_ranges_postcondition(m, &original, conf_c, "unmark_as_read") < 0)
{
kom_log("this was triggered by an attempt to mark %lu as not read\n",
(unsigned long)lno);
}
#endif
return retval;
}
static Success
check_range_list(const struct read_range_list *read_ranges)
{
Local_text_no last = 0;
unsigned short i;
if (read_ranges->length > param.max_read_ranges)
{
kom_errno = KOM_LONG_ARRAY;
err_stat = param.max_read_ranges;
return FAILURE;
}
for (i = 0; i < read_ranges->length; i++)
{
if (read_ranges->ranges[i].first_read >
read_ranges->ranges[i].last_read)
{
kom_errno = KOM_INVALID_RANGE;
err_stat = i;
return FAILURE;
}
if (read_ranges->ranges[i].first_read <= last)
{
if (read_ranges->ranges[i].first_read == 0)
kom_errno = KOM_LOCAL_TEXT_ZERO;
else
kom_errno = KOM_INVALID_RANGE_LIST;
err_stat = i;
return FAILURE;
}
sfree(original.read_ranges);
last = read_ranges->ranges[i].last_read;
}
return OK;
}
Success
set_read_ranges(Conf_no conference,
const struct read_range_list *read_ranges)
{
Membership * m;
Conference * conf_c;
Success retval = OK;
#ifdef DEBUG_MARK_AS_READ
Membership original;
#endif
if (check_range_list(read_ranges) == FAILURE)
return FAILURE;
CHK_CONNECTION(FAILURE);
CHK_LOGIN(FAILURE);
GET_C_STAT(conf_c, conference, FAILURE);
if ((m = locate_membership(conference, ACT_P)) == NULL)
{
set_conf_errno(active_connection, conference, KOM_NOT_MEMBER);
return FAILURE;
}
#ifdef DEBUG_MARK_AS_READ
read_ranges_precondition(m, &original, conf_c, "set_read_ranges");
#endif
if (read_ranges->length == 0)
{
if (m->no_of_read_ranges != 0)
{
sfree(m->read_ranges);
m->read_ranges = NULL;
m->no_of_read_ranges = 0;
/* FIXME (bug 877): mark_as_read uses mark_conference_as_changed
instead. If that is proper, then this line is wrong. */
mark_person_as_changed(ACTPERS);
}
}
else if (read_ranges->ranges[read_ranges->length-1].last_read
>= l2g_first_appendable_key(&conf_c->texts))
{
kom_errno = KOM_NO_SUCH_LOCAL_TEXT;
err_stat = read_ranges->ranges[read_ranges->length-1].last_read;
retval = FAILURE;
}
else
{
if (m->no_of_read_ranges != read_ranges->length)
{
m->no_of_read_ranges = read_ranges->length;
m->read_ranges = srealloc(
m->read_ranges,
m->no_of_read_ranges * sizeof(m->read_ranges[0]));
}
memcpy(m->read_ranges, read_ranges->ranges,
m->no_of_read_ranges * sizeof(m->read_ranges[0]));
adjust_read(m, conf_c);
/* FIXME (bug 877): mark_as_read uses mark_conference_as_changed
instead. If that is proper, then this line is wrong. */
mark_person_as_changed(ACTPERS);
}
#ifdef DEBUG_MARK_AS_READ
read_ranges_postcondition(m, &original, conf_c, "set_read_ranges");
#endif
return retval;
}
/*
* Ask what conferences a person is a member of.
*/
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment