case PRIVBCB_ITEM_LEAVE_FUNC_PENDING:
g_assert(TRUE==value || FALSE==value);
privbcb->leave_func_pending=value;
+ if (value)
+ g_assert(privbcb->ref_count==1);
break;
case PRIVBCB_ITEM_REF_COUNT:
+ /* Forbid reincarnation of 'leave_func_pending' privbcb.
+ * Allow some of its 'ref_count' handling to properly clean it up.
+ */
+ if (privbcb->leave_func_pending)
+ g_assert((privbcb->ref_count==1 && value==-1)
+ || (privbcb->ref_count==0 && value==+1));
g_assert(privbcb->ref_count>=0);
privbcb->ref_count+=value;
g_assert(privbcb->ref_count>=0);
captive_privbcb_flush(privbcb);
}
+static void CcUnpinData_leave_func(struct private_bcb *privbcb_stop_at);
+
void captive_cc_flush(void)
{
gboolean flushed;
private_bcb_hash_init();
do {
+ /* Trace it by g_tree first to attempt to keep LSN ordering */
+ CcUnpinData_leave_func(NULL);
flushed=FALSE;
g_hash_table_foreach(
private_bcb_hash, /* hash_table */
return TRUE; /* stop the traversal */
}
-static void CcUnpinData_leave_func(gpointer user_data /* unused */)
+static void CcUnpinData_leave_func(struct private_bcb *privbcb_stop_at) /* NULL to traverse the whole tree */
{
struct private_bcb *privbcb;
gboolean errbool;
private_bcb_flush_tree_init();
- for (;;) {
+ do {
privbcb=NULL;
g_tree_foreach(private_bcb_flush_tree,
(GTraverseFunc)CcUnpinData_leave_func_foreach_get_first, /* func */
privbcb->FileObject,(guint64)privbcb->MappedFileOffset.QuadPart,(gulong)privbcb->MappedLength,(int)privbcb->ref_count,
(int)privbcb->leave_func_pending);
- if (!privbcb->leave_func_pending) {
+ /* Do not stop at not yet modified buffers if not privbcb_stop_at==NULL,
+ * privbcb_stop_at==NULL is used to flush the whole cache.
+ */
+ if (privbcb_stop_at && !privbcb->leave_func_pending) {
g_assert(privbcb->lsn_valid); /* cannout skip LSN-valid BCB */
break;
}
- g_assert(privbcb->leave_func_pending==TRUE);
+ g_assert(!privbcb_stop_at || privbcb->leave_func_pending==TRUE);
privbcb_set(privbcb,PRIVBCB_ITEM_LEAVE_FUNC_PENDING,FALSE);
privbcb_set(privbcb,PRIVBCB_ITEM_REF_COUNT,-1);
- if (privbcb->ref_count) {
+
+ /* Do not flush modified buffers if not privbcb_stop_at==NULL,
+ * privbcb_stop_at==NULL is used to flush the whole cache.
+ */
+ if (privbcb_stop_at && privbcb->ref_count) {
if (privbcb->lsn_valid) /* cannout skip LSN-valid BCB */
break;
continue;
continue;
}
+ /* Clear it out of 'private_bcb_flush_tree' during global buffers flush. */
+ if (!privbcb_stop_at) {
+ privbcb_set(privbcb,PRIVBCB_ITEM_REF_COUNT,-privbcb->ref_count);
+ privbcb_set(privbcb,PRIVBCB_ITEM_LSN_VALID,FALSE);
+ }
+
g_assert(privbcb->leave_func_pending==FALSE);
g_assert(privbcb->ref_count==0);
g_assert(NULL==g_tree_lookup(private_bcb_flush_tree,privbcb));
errbool=g_hash_table_remove(private_bcb_hash,privbcb->PublicBcb);
g_assert(errbool==TRUE);
- }
+ } while (!privbcb_stop_at || privbcb!=privbcb_stop_at);
}
/**
privbcb_set(privbcb,PRIVBCB_ITEM_LEAVE_FUNC_PENDING,TRUE);
captive_leave_register(
(captive_leave_func)CcUnpinData_leave_func, /* func */
- privbcb); /* data; unused */
+ privbcb); /* data; privbcb_stop_at */
}
if (captive_cc_unmounting)