cpsv: To update checkpoint user number for each node [#1669] V4

Problem:
-------
The saCkptCheckpointNumOpeners is not updated when a node which has a checkpoint client restarts.

Solution:
--------
Currently CPD doesn't store number of user on each node. This patch updates CPD to update information
about users on each node for each checkpoint. When a node restarts, the CPD update the total number of
users for a checkpoint accordingly. This is reflected on saCkptCheckpointNumOpeners attribute correctly.

diff --git a/osaf/libs/common/cpsv/include/cpd_cb.h b/osaf/libs/common/cpsv/include/cpd_cb.h
--- a/osaf/libs/common/cpsv/include/cpd_cb.h
+++ b/osaf/libs/common/cpsv/include/cpd_cb.h
@@ -92,6 +92,8 @@ typedef struct cpd_ckpt_info_node {
 	uint32_t num_users;
 	uint32_t num_readers;
 	uint32_t num_writers;
+	uint32_t node_users_cnt;
+	CPD_NODE_USER_INFO *node_users;
 
 	/* for imm */
 	SaUint32T ckpt_used_size;
diff --git a/osaf/libs/common/cpsv/include/cpd_proc.h b/osaf/libs/common/cpsv/include/cpd_proc.h
--- a/osaf/libs/common/cpsv/include/cpd_proc.h
+++ b/osaf/libs/common/cpsv/include/cpd_proc.h
@@ -108,5 +108,8 @@ uint32_t cpd_mbcsv_enc_async_update(CPD_
 uint32_t cpd_mbcsv_close(CPD_CB *cb);
 bool cpd_is_noncollocated_replica_present_on_payload(CPD_CB *cb, CPD_CKPT_INFO_NODE *ckpt_node);
 uint32_t cpd_ckpt_reploc_imm_object_delete(CPD_CB *cb,  CPD_CKPT_REPLOC_INFO *ckpt_reploc_node ,bool is_unlink_set);
+void cpd_proc_increase_node_user_info(CPD_CKPT_INFO_NODE *ckpt_node, MDS_DEST cpnd_dest, SaCkptCheckpointOpenFlagsT open_flags);
+void cpd_proc_decrease_node_user_info(CPD_CKPT_INFO_NODE *ckpt_node, MDS_DEST cpnd_dest, SaCkptCheckpointOpenFlagsT open_flags);
+void cpd_proc_update_user_info_when_node_down(CPD_CB *cb, NODE_ID node_id);
 uint32_t cpd_proc_ckpt_update_post(CPD_CB *cb);
 #endif
diff --git a/osaf/libs/common/cpsv/include/cpd_red.h b/osaf/libs/common/cpsv/include/cpd_red.h
--- a/osaf/libs/common/cpsv/include/cpd_red.h
+++ b/osaf/libs/common/cpsv/include/cpd_red.h
@@ -64,6 +64,18 @@ typedef struct cpd_a2s_ckpt_usr_info {
 
 } CPD_A2S_CKPT_USR_INFO;
 
+typedef struct cpd_a2s_ckpt_usr_info_2 {
+	SaCkptCheckpointHandleT ckpt_id;
+	uint32_t num_user;
+	uint32_t num_writer;
+	uint32_t num_reader;
+	uint32_t num_sections;
+	uint32_t ckpt_on_scxb1;
+	uint32_t ckpt_on_scxb2;
+	uint32_t node_users_cnt;
+	CPD_NODE_USER_INFO *node_list;
+} CPD_A2S_CKPT_USR_INFO_2;
+
 typedef struct cpd_mbcsv_msg {
 	CPD_MBCSV_MSG_TYPE type;
 	union {
@@ -76,6 +88,7 @@ typedef struct cpd_mbcsv_msg {
 		CPD_A2S_CKPT_UNLINK ckpt_ulink;
 		CPD_A2S_CKPT_USR_INFO usr_info;
 		CPSV_CKPT_DEST_INFO dest_down;
+		CPD_A2S_CKPT_USR_INFO_2 usr_info_2;
 	} info;
 } CPD_MBCSV_MSG;
 
diff --git a/osaf/libs/common/cpsv/include/cpsv_evt.h b/osaf/libs/common/cpsv/include/cpsv_evt.h
--- a/osaf/libs/common/cpsv/include/cpsv_evt.h
+++ b/osaf/libs/common/cpsv/include/cpsv_evt.h
@@ -840,6 +840,14 @@ typedef struct cpd_tmr_info {
 	} info;
 } CPD_TMR_INFO;
 
+typedef struct cpd_node_user_info {
+	MDS_DEST dest;
+	uint32_t num_users;
+	uint32_t num_writers;
+	uint32_t num_readers;
+	struct cpd_node_user_info *next;
+} CPD_NODE_USER_INFO;
+
 /******************************************************************************
  CPD Event Data Structures
  ******************************************************************************/
diff --git a/osaf/services/saf/cpsv/cpd/cpd_db.c b/osaf/services/saf/cpsv/cpd/cpd_db.c
--- a/osaf/services/saf/cpsv/cpd/cpd_db.c
+++ b/osaf/services/saf/cpsv/cpd/cpd_db.c
@@ -137,6 +137,7 @@ uint32_t cpd_ckpt_node_delete(CPD_CB *cb
 {
 	uint32_t rc = NCSCC_RC_SUCCESS;
 	CPD_NODE_REF_INFO *nref_info, *next_info;
+	CPD_NODE_USER_INFO *node_user, *next_node_user;
 
 	TRACE_ENTER();
 
@@ -153,6 +154,13 @@ uint32_t cpd_ckpt_node_delete(CPD_CB *cb
 		nref_info = next_info;
 	}
 
+	node_user = ckpt_node->node_users;
+	while (node_user) {
+		next_node_user = node_user->next;
+		free(node_user);
+		node_user = next_node_user;
+	}
+
 	/* delete imm ckpt runtime object */
 	if ((cb->ha_state == SA_AMF_HA_ACTIVE) && (ckpt_node->is_unlink_set != true)) {
 		if (immutil_saImmOiRtObjectDelete(cb->immOiHandle, &ckpt_node->ckpt_name) != SA_AIS_OK) {
@@ -1258,8 +1266,11 @@ void cpd_clm_cluster_track_cb(const SaCl
 		/* 2. Check the HA_STATE */
 		for (counter = 0; counter < notificationBuffer->numberOfItems; counter++) {
 			if (notificationBuffer->notification[counter].clusterChange == SA_CLM_NODE_LEFT) {
+				node_id = notificationBuffer->notification[counter].clusterNode.nodeId;
+
+				cpd_proc_update_user_info_when_node_down(cb, node_id);
+
 				if (cb->ha_state == SA_AMF_HA_ACTIVE) {
-					node_id = notificationBuffer->notification[counter].clusterNode.nodeId;
 					key = node_id;
 					cpnd_info_node = (CPD_CPND_INFO_NODE *)
 					    ncs_patricia_tree_get(&cb->cpnd_tree, (uint8_t *)&key);
@@ -1267,7 +1278,6 @@ void cpd_clm_cluster_track_cb(const SaCl
 						cpd_process_cpnd_down(cb, &cpnd_info_node->cpnd_dest);
 					}
 				} else if (cb->ha_state == SA_AMF_HA_STANDBY) {
-					node_id = notificationBuffer->notification[counter].clusterNode.nodeId;
 					key = node_id;
 					cpnd_info_node = (CPD_CPND_INFO_NODE *)
 					    ncs_patricia_tree_get(&cb->cpnd_tree, (uint8_t *)&key);
diff --git a/osaf/services/saf/cpsv/cpd/cpd_evt.c b/osaf/services/saf/cpsv/cpd/cpd_evt.c
--- a/osaf/services/saf/cpsv/cpd/cpd_evt.c
+++ b/osaf/services/saf/cpsv/cpd/cpd_evt.c
@@ -249,6 +249,7 @@ static uint32_t cpd_evt_proc_ckpt_create
 		ckpt_node->num_writers++;
 
 	ckpt_node->num_users++;
+	cpd_proc_increase_node_user_info(ckpt_node, sinfo->dest, ckpt_create->ckpt_flags);
 
 	cb->is_db_upd = true;
 
@@ -447,6 +448,8 @@ static uint32_t cpd_evt_proc_ckpt_usr_in
 			ckpt_node->num_readers++;
 		if (evt->info.ckpt_usr_info.ckpt_flags & SA_CKPT_CHECKPOINT_WRITE)
 			ckpt_node->num_writers++;
+
+		cpd_proc_increase_node_user_info(ckpt_node, sinfo->dest, evt->info.ckpt_usr_info.ckpt_flags);
 	}
 	else if (evt->info.ckpt_usr_info.info_type == CPSV_USR_INFO_CKPT_OPEN) {
 
@@ -456,6 +459,8 @@ static uint32_t cpd_evt_proc_ckpt_usr_in
 			ckpt_node->num_readers++;
 		if (evt->info.ckpt_usr_info.ckpt_flags & SA_CKPT_CHECKPOINT_WRITE)
 			ckpt_node->num_writers++;
+
+		cpd_proc_increase_node_user_info(ckpt_node, sinfo->dest, evt->info.ckpt_usr_info.ckpt_flags);
 	}
 	
 	if (evt->info.ckpt_usr_info.info_type == CPSV_USR_INFO_CKPT_CLOSE_LAST) {
@@ -493,6 +498,8 @@ static uint32_t cpd_evt_proc_ckpt_usr_in
 			ckpt_node->num_readers--;
 		if (evt->info.ckpt_usr_info.ckpt_flags & SA_CKPT_CHECKPOINT_WRITE)
 			ckpt_node->num_writers--;
+
+		cpd_proc_decrease_node_user_info(ckpt_node, sinfo->dest, evt->info.ckpt_usr_info.ckpt_flags);
 	}
 	else if (evt->info.ckpt_usr_info.info_type == CPSV_USR_INFO_CKPT_CLOSE) {
 
@@ -503,6 +510,7 @@ static uint32_t cpd_evt_proc_ckpt_usr_in
 		if (evt->info.ckpt_usr_info.ckpt_flags & SA_CKPT_CHECKPOINT_WRITE)
 			ckpt_node->num_writers--;
 
+		cpd_proc_decrease_node_user_info(ckpt_node, sinfo->dest, evt->info.ckpt_usr_info.ckpt_flags);
 	}
 
 	cpd_a2s_ckpt_usr_info(cb, ckpt_node);
diff --git a/osaf/services/saf/cpsv/cpd/cpd_mbcsv.c b/osaf/services/saf/cpsv/cpd/cpd_mbcsv.c
--- a/osaf/services/saf/cpsv/cpd/cpd_mbcsv.c
+++ b/osaf/services/saf/cpsv/cpd/cpd_mbcsv.c
@@ -24,6 +24,10 @@
 
 #include "cpd.h"
 
+static void cpd_mbcsv_enc_a2s_usr_info_2(NCS_UBAID *io_uba, CPD_A2S_CKPT_USR_INFO_2 *usr_info);
+static void cpd_mbcsv_dec_a2s_usr_info_2(NCS_UBAID *io_uba, CPD_A2S_CKPT_USR_INFO_2 *usr_info);
+
+
 /**********************************************************************************************
  * Name                   : cpd_mbcsv_async_update
  *
@@ -439,12 +443,7 @@ uint32_t cpd_mbcsv_enc_async_update(CPD_
 
 	case CPD_A2S_MSG_CKPT_USR_INFO:
 		cpd_msg = (CPD_MBCSV_MSG *)NCS_INT64_TO_PTR_CAST(arg->info.encode.io_reo_hdl);
-		rc = m_NCS_EDU_EXEC(&cb->edu_hdl, FUNC_NAME(CPD_A2S_CKPT_USR_INFO), &arg->info.encode.io_uba,
-				    EDP_OP_TYPE_ENC, &cpd_msg->info.usr_info, &ederror);
-		if (rc != NCSCC_RC_SUCCESS) {
-			TRACE_4("edu exec async userinfo failed ");
-			rc = NCSCC_RC_FAILURE;
-		}
+		cpd_mbcsv_enc_a2s_usr_info_2(&arg->info.encode.io_uba, &cpd_msg->info.usr_info_2);
 		break;
 
 	case CPD_A2S_MSG_CKPT_DEST_DOWN:
@@ -744,7 +743,6 @@ uint32_t cpd_mbcsv_dec_async_update(CPD_
 	CPSV_CKPT_DEST_INFO *ckpt_dest_add = NULL;
 	CPSV_CKPT_DEST_INFO *ckpt_dest_del = NULL;
 	CPSV_CKPT_DEST_INFO *ckpt_dest_down = NULL;
-	CPD_A2S_CKPT_USR_INFO *ckpt_usr_info = NULL;
 	uint32_t evt_type, rc = NCSCC_RC_SUCCESS;
 	EDU_ERR ederror = 0;
 
@@ -889,16 +887,8 @@ uint32_t cpd_mbcsv_dec_async_update(CPD_
 		break;
 
 	case CPD_A2S_MSG_CKPT_USR_INFO:
-		ckpt_usr_info = &cpd_msg->info.usr_info;
-		rc = m_NCS_EDU_EXEC(&cb->edu_hdl, FUNC_NAME(CPD_A2S_CKPT_USR_INFO), &arg->info.decode.i_uba,
-				    EDP_OP_TYPE_DEC, &ckpt_usr_info, &ederror);
-		if (rc != NCSCC_RC_SUCCESS) {
-			TRACE_4("edu exec async dest del failed"); 
-			rc = NCSCC_RC_FAILURE;
-			goto end;
-		}
 		cpd_msg->type = evt_type;
-		cpd_msg->info.usr_info = *ckpt_usr_info;
+		cpd_mbcsv_dec_a2s_usr_info_2(&arg->info.decode.i_uba, &cpd_msg->info.usr_info_2);
 		rc = cpd_process_sb_msg(cb, cpd_msg);
 
 		if (rc != NCSCC_RC_SUCCESS) {
@@ -1154,3 +1144,79 @@ uint32_t cpd_mbcsv_decode_proc(NCS_MBCSV
 	}
 
 }
+
+/**********************************************************************************************
+ * Name                   : cpd_mbcsv_enc_a2s_usr_info_2
+ *
+ * Description            : This function encodes the message CPD_A2S_MSG_CKPT_USR_INFO
+ *
+ * Return Values          : None
+ *
+ * Notes                  : None
+**********************************************************************************************/
+void cpd_mbcsv_enc_a2s_usr_info_2(NCS_UBAID *io_uba, CPD_A2S_CKPT_USR_INFO_2 *usr_info)
+{
+	TRACE_ENTER();
+
+	osaf_encode_uint64(io_uba, usr_info->ckpt_id);
+	osaf_encode_uint32(io_uba, usr_info->num_user);
+	osaf_encode_uint32(io_uba, usr_info->num_writer);
+	osaf_encode_uint32(io_uba, usr_info->num_reader);
+	osaf_encode_uint32(io_uba, usr_info->num_sections);
+	osaf_encode_uint32(io_uba, usr_info->ckpt_on_scxb1);
+	osaf_encode_uint32(io_uba, usr_info->ckpt_on_scxb2);
+	osaf_encode_uint32(io_uba, usr_info->node_users_cnt);
+
+	int i = 0;
+	for (i = 0; i < usr_info->node_users_cnt; i++) {
+		osaf_encode_uint64(io_uba, usr_info->node_list[i].dest);
+		osaf_encode_uint32(io_uba, usr_info->node_list[i].num_users);
+		osaf_encode_uint32(io_uba, usr_info->node_list[i].num_writers);
+		osaf_encode_uint32(io_uba, usr_info->node_list[i].num_readers);
+	}
+
+	TRACE_LEAVE();
+}
+
+/**********************************************************************************************
+ * Name                   : cpd_mbcsv_dec_a2s_usr_info_2
+ *
+ * Description            : This function decodes the message CPD_A2S_MSG_CKPT_USR_INFO
+ *
+ *
+ * Return Values          : None
+ *
+ * Notes                  : None
+**********************************************************************************************/
+void cpd_mbcsv_dec_a2s_usr_info_2(NCS_UBAID *io_uba, CPD_A2S_CKPT_USR_INFO_2 *usr_info)
+{
+	TRACE_ENTER();
+
+	osaf_decode_uint64(io_uba, (uint64_t *) &usr_info->ckpt_id);
+	osaf_decode_uint32(io_uba, &usr_info->num_user);
+	osaf_decode_uint32(io_uba, &usr_info->num_writer);
+	osaf_decode_uint32(io_uba, &usr_info->num_reader);
+	osaf_decode_uint32(io_uba, &usr_info->num_sections);
+	osaf_decode_uint32(io_uba, &usr_info->ckpt_on_scxb1);
+	osaf_decode_uint32(io_uba, &usr_info->ckpt_on_scxb2);
+	osaf_decode_uint32(io_uba, &usr_info->node_users_cnt);
+
+	// Handle old message
+	if (!usr_info->node_users_cnt) {
+		TRACE_LEAVE();
+		return;
+	}
+
+	int i = 0;
+	CPD_NODE_USER_INFO *node_list = malloc(usr_info->node_users_cnt * sizeof(CPD_NODE_USER_INFO));
+	for (i = 0; i < usr_info->node_users_cnt; i++) {
+		osaf_decode_uint64(io_uba, &node_list[i].dest);
+		osaf_decode_uint32(io_uba, &node_list[i].num_users);
+		osaf_decode_uint32(io_uba, &node_list[i].num_writers);
+		osaf_decode_uint32(io_uba, &node_list[i].num_readers);
+	}
+
+	usr_info->node_list = node_list;
+
+	TRACE_LEAVE();
+}
diff --git a/osaf/services/saf/cpsv/cpd/cpd_proc.c b/osaf/services/saf/cpsv/cpd/cpd_proc.c
--- a/osaf/services/saf/cpsv/cpd/cpd_proc.c
+++ b/osaf/services/saf/cpsv/cpd/cpd_proc.c
@@ -1581,3 +1581,151 @@ void cpd_proc_broadcast_rdset_stop(SaCkp
 	send_evt.info.cpnd.info.rdset.type = CPSV_CKPT_RDSET_STOP;
 	cpd_mds_bcast_send(cb, &send_evt, NCSMDS_SVC_ID_CPND);
 }
+
+/******************************************************************************************
+ * Name          : cpd_proc_increase_node_ref_user_info
+ *
+ * Description   : This routine increases number of user, writer and reader for 
+ *                 the specified cpnd node reference
+ *
+ * Return Values : None 
+ *
+ * Notes         : None
+******************************************************************************************/
+void cpd_proc_increase_node_user_info(CPD_CKPT_INFO_NODE *ckpt_node, MDS_DEST cpnd_dest, 
+		SaCkptCheckpointOpenFlagsT open_flags)
+{
+	CPD_NODE_USER_INFO *node_user = ckpt_node->node_users;
+	CPD_NODE_USER_INFO *last_node_user = NULL;
+
+	TRACE_ENTER();
+
+	if (ckpt_node->node_users_cnt == 0) {
+		node_user = malloc(sizeof(CPD_NODE_USER_INFO));
+		memset(node_user, 0, sizeof(CPD_NODE_USER_INFO));
+		node_user->dest = cpnd_dest;
+
+		if (open_flags & SA_CKPT_CHECKPOINT_READ)
+			node_user->num_readers++;
+		if (open_flags & SA_CKPT_CHECKPOINT_WRITE)
+			node_user->num_writers++;
+
+		node_user->num_users++;
+		node_user->next = NULL;
+		ckpt_node->node_users = node_user;
+		ckpt_node->node_users_cnt++;
+		TRACE_LEAVE();
+		return;
+	}
+
+	while (node_user) {
+		if (node_user->dest == cpnd_dest) {
+			if (open_flags & SA_CKPT_CHECKPOINT_READ)
+				node_user->num_readers++;
+			if (open_flags & SA_CKPT_CHECKPOINT_WRITE)
+				node_user->num_writers++;
+
+			node_user->num_users++;
+			TRACE_LEAVE();
+			return;
+		}
+		last_node_user = node_user;
+		node_user = node_user->next;
+	}
+
+	/* Add node user */
+	node_user = malloc(sizeof(CPD_NODE_USER_INFO));
+	memset(node_user, 0, sizeof(CPD_NODE_USER_INFO));
+	node_user->dest = cpnd_dest;
+
+	if (open_flags & SA_CKPT_CHECKPOINT_READ)
+		node_user->num_readers++;
+	if (open_flags & SA_CKPT_CHECKPOINT_WRITE)
+		node_user->num_writers++;
+
+	node_user->num_users++;
+	node_user->next = NULL;
+	last_node_user->next = node_user;
+	ckpt_node->node_users_cnt++;
+
+	TRACE_LEAVE();
+}
+
+/******************************************************************************************
+ * Name          : cpd_proc_decrease_node_ref_user_info
+ *
+ * Description   : This routine decreases number of user, writer and reader for 
+ *                 the specified cpnd node reference
+ *
+ * Return Values : None 
+ *
+ * Notes         : None
+******************************************************************************************/
+void cpd_proc_decrease_node_user_info(CPD_CKPT_INFO_NODE *ckpt_node, MDS_DEST cpnd_dest, 
+		SaCkptCheckpointOpenFlagsT open_flags)
+{
+	CPD_NODE_USER_INFO *node_user = ckpt_node->node_users;
+
+	TRACE_ENTER();
+
+	while (node_user) {
+		if (node_user->dest == cpnd_dest) {
+			if (node_user->num_users == 0) {
+				LOG_ER("cpd_proc_decrease_node_user_info failed - no user on node id 0x%X", 
+						m_NCS_NODE_ID_FROM_MDS_DEST(cpnd_dest));
+				TRACE_LEAVE();
+				return;
+			}
+
+			if (open_flags & SA_CKPT_CHECKPOINT_READ)
+				node_user->num_readers--;
+			if (open_flags & SA_CKPT_CHECKPOINT_WRITE)
+				node_user->num_writers--;
+
+			node_user->num_users--;
+			TRACE_LEAVE();
+			return;
+		}
+		node_user = node_user->next;
+	}
+
+	TRACE_LEAVE();
+}
+
+/******************************************************************************************
+ * Name          : cpd_proc_update_user_info_when_node_down
+ *
+ * Description   : This routine updates number of user, writer and reader in case node down 
+ *
+ * Return Values : None 
+ *
+ * Notes         : None
+******************************************************************************************/
+void cpd_proc_update_user_info_when_node_down(CPD_CB *cb, NODE_ID node_id)
+{
+	CPD_CKPT_INFO_NODE *ckpt_node;
+	TRACE_ENTER();
+	
+	cpd_ckpt_node_getnext(&cb->ckpt_tree, NULL, &ckpt_node);
+	while (ckpt_node) {
+		SaCkptCheckpointHandleT prev_ckpt_hdl = ckpt_node->ckpt_id;
+		CPD_NODE_USER_INFO *node_user;
+
+		for (node_user = ckpt_node->node_users; node_user != NULL; node_user = node_user->next) {
+			if (node_id == m_NCS_NODE_ID_FROM_MDS_DEST(node_user->dest)) {
+				ckpt_node->num_users -= node_user->num_users;
+				ckpt_node->num_writers -= node_user->num_writers;
+				ckpt_node->num_readers -= node_user->num_readers;
+
+				node_user->num_users = 0;
+				node_user->num_writers = 0;
+				node_user->num_readers = 0;
+				break;
+			}
+		}
+
+		cpd_ckpt_node_getnext(&cb->ckpt_tree, &prev_ckpt_hdl, &ckpt_node);
+	}
+
+	TRACE_LEAVE();
+}
diff --git a/osaf/services/saf/cpsv/cpd/cpd_red.c b/osaf/services/saf/cpsv/cpd/cpd_red.c
--- a/osaf/services/saf/cpsv/cpd/cpd_red.c
+++ b/osaf/services/saf/cpsv/cpd/cpd_red.c
@@ -301,18 +301,34 @@ void cpd_a2s_ckpt_dest_del(CPD_CB *cb, S
 void cpd_a2s_ckpt_usr_info(CPD_CB *cb, CPD_CKPT_INFO_NODE *ckpt_node)
 {
 	CPD_MBCSV_MSG cpd_msg;
+	int count = 0;
 	uint32_t rc = SA_AIS_OK;
 	memset(&cpd_msg, '\0', sizeof(CPD_MBCSV_MSG));
 
 	TRACE_ENTER();
 	cpd_msg.type = CPD_A2S_MSG_CKPT_USR_INFO;
-	cpd_msg.info.usr_info.ckpt_id = ckpt_node->ckpt_id;
-	cpd_msg.info.usr_info.num_user = ckpt_node->num_users;
-	cpd_msg.info.usr_info.num_writer = ckpt_node->num_writers;
-	cpd_msg.info.usr_info.num_reader = ckpt_node->num_readers;
-	cpd_msg.info.usr_info.num_sections = ckpt_node->num_sections;
-	cpd_msg.info.usr_info.ckpt_on_scxb1 = ckpt_node->ckpt_on_scxb1;
-	cpd_msg.info.usr_info.ckpt_on_scxb2 = ckpt_node->ckpt_on_scxb2;
+	cpd_msg.info.usr_info_2.ckpt_id = ckpt_node->ckpt_id;
+	cpd_msg.info.usr_info_2.num_user = ckpt_node->num_users;
+	cpd_msg.info.usr_info_2.num_writer = ckpt_node->num_writers;
+	cpd_msg.info.usr_info_2.num_reader = ckpt_node->num_readers;
+	cpd_msg.info.usr_info_2.num_sections = ckpt_node->num_sections;
+	cpd_msg.info.usr_info_2.ckpt_on_scxb1 = ckpt_node->ckpt_on_scxb1;
+	cpd_msg.info.usr_info_2.ckpt_on_scxb2 = ckpt_node->ckpt_on_scxb2;
+
+	if (ckpt_node->node_users_cnt) {
+		CPD_NODE_USER_INFO *node_user = ckpt_node->node_users;
+		cpd_msg.info.usr_info_2.node_users_cnt = ckpt_node->node_users_cnt;
+		cpd_msg.info.usr_info_2.node_list = malloc(ckpt_node->node_users_cnt * sizeof(CPD_NODE_USER_INFO));
+		memset(cpd_msg.info.usr_info_2.node_list, '\0', (sizeof(CPD_NODE_USER_INFO) * ckpt_node->node_users_cnt));
+
+		for (count = 0; count < ckpt_node->node_users_cnt; count++) {
+			cpd_msg.info.usr_info_2.node_list[count].dest = node_user->dest;
+			cpd_msg.info.usr_info_2.node_list[count].num_users = node_user->num_users;
+			cpd_msg.info.usr_info_2.node_list[count].num_readers = node_user->num_readers;
+			cpd_msg.info.usr_info_2.node_list[count].num_writers = node_user->num_writers;
+			node_user = node_user->next;
+		}
+	}
 
 	rc = cpd_mbcsv_async_update(cb, &cpd_msg);
 	if (rc != SA_AIS_OK)
diff --git a/osaf/services/saf/cpsv/cpd/cpd_sbevt.c b/osaf/services/saf/cpsv/cpd/cpd_sbevt.c
--- a/osaf/services/saf/cpsv/cpd/cpd_sbevt.c
+++ b/osaf/services/saf/cpsv/cpd/cpd_sbevt.c
@@ -549,14 +549,15 @@ uint32_t cpd_sb_proc_ckpt_dest_add(CPD_C
 /**********************************************************************************
 *  Name :  cpd_sb_proc_ckpt_usrinfo
 *
-*  Description : This routine will set the active replica flag of the checkpoint
+*  Description : This routine will update user information of the checkpoint
+*                This version includes user information of each node
 *
 *  Arguments   : CPD_MBCSV_MSG - mbcsv message
-                                                                                                                             
+*
 *  Return Values : Success / Error
-                                                                                                                             
+*
 *  Notes : None
-                                                                                                                             
+*
 **********************************************************************************/
 uint32_t cpd_sb_proc_ckpt_usrinfo(CPD_CB *cb, CPD_MBCSV_MSG *msg)
 {
@@ -569,12 +570,48 @@ uint32_t cpd_sb_proc_ckpt_usrinfo(CPD_CB
 		return NCSCC_RC_FAILURE;
 	}
 
-	ckpt_node->num_users = msg->info.usr_info.num_user;
-	ckpt_node->num_writers = msg->info.usr_info.num_writer;
-	ckpt_node->num_readers = msg->info.usr_info.num_reader;
-	ckpt_node->num_sections = msg->info.usr_info.num_sections;
-	ckpt_node->ckpt_on_scxb1 = msg->info.usr_info.ckpt_on_scxb1;
-	ckpt_node->ckpt_on_scxb2 = msg->info.usr_info.ckpt_on_scxb2;
+	ckpt_node->num_users = msg->info.usr_info_2.num_user;
+	ckpt_node->num_writers = msg->info.usr_info_2.num_writer;
+	ckpt_node->num_readers = msg->info.usr_info_2.num_reader;
+	ckpt_node->num_sections = msg->info.usr_info_2.num_sections;
+	ckpt_node->ckpt_on_scxb1 = msg->info.usr_info_2.ckpt_on_scxb1;
+	ckpt_node->ckpt_on_scxb2 = msg->info.usr_info_2.ckpt_on_scxb2;
+
+	/* Free the old node_users */
+	CPD_NODE_USER_INFO *node_user = ckpt_node->node_users;
+	CPD_NODE_USER_INFO *prev_node_user = NULL;
+
+	while (node_user) {
+		CPD_NODE_USER_INFO *prev_node_user = node_user;
+		node_user = node_user->next;
+		free(prev_node_user);
+	}
+	ckpt_node->node_users = NULL;
+
+	if (!msg->info.usr_info_2.node_users_cnt) {
+		TRACE_LEAVE();
+		return NCSCC_RC_SUCCESS;
+	}
+
+	/* Update the node_users */
+	int i = 0;
+	for (i = 0; i < msg->info.usr_info_2.node_users_cnt; i++) {
+		CPD_NODE_USER_INFO *node_user = malloc(sizeof(CPD_NODE_USER_INFO));
+		if (prev_node_user != NULL)
+			prev_node_user->next = node_user;
+
+		node_user->dest = msg->info.usr_info_2.node_list[i].dest;
+		node_user->num_users = msg->info.usr_info_2.node_list[i].num_users;
+		node_user->num_readers = msg->info.usr_info_2.node_list[i].num_readers;
+		node_user->num_writers = msg->info.usr_info_2.node_list[i].num_writers;
+		node_user->next = NULL;
+		prev_node_user = node_user;
+
+		if (i == 0)
+			ckpt_node->node_users = node_user;
+	}
+
+	free(msg->info.usr_info_2.node_list);
 
 	TRACE_LEAVE();
 	return NCSCC_RC_SUCCESS;
