/* This called for TP and non-TP, but not for ZTP */ void jnl_write_logical(sgmnt_addrs *csa, jnl_format_buffer *jfb) { struct_jrec_upd *jrec; jnl_private_control *jpc; /* If REPL_WAS_ENABLED(csa) is TRUE, then we would not have gone through the code that initializes * jgbl.gbl_jrec_time or jpc->pini_addr. But in this case, we are not writing the journal record * to the journal buffer or journal file but write it only to the journal pool from where it gets * sent across to the update process that does not care about these fields so it is ok to leave them as is. */ jpc = csa->jnl; assert((0 != jpc->pini_addr) || REPL_WAS_ENABLED(csa)); assert(jgbl.gbl_jrec_time || REPL_WAS_ENABLED(csa)); assert(csa->now_crit); assert(IS_SET_KILL_ZKILL(jfb->rectype)); assert(!IS_ZTP(jfb->rectype)); jrec = (struct_jrec_upd *)jfb->buff; jrec->prefix.pini_addr = (0 == jpc->pini_addr) ? JNL_HDR_LEN : jpc->pini_addr; jrec->prefix.tn = csa->ti->curr_tn; jrec->prefix.time = jgbl.gbl_jrec_time; jrec->prefix.checksum = jfb->checksum; if (jgbl.forw_phase_recovery) { QWASSIGN(jrec->token_seq, jgbl.mur_jrec_token_seq); } else { /* t_end and tp_tend already has set token or jnl_seqno into jnl_fence_ctl.token */ QWASSIGN(jrec->token_seq.token, jnl_fence_ctl.token); } JNL_WRITE_APPROPRIATE(csa, jpc, jfb->rectype, (jnl_record *)jrec, NULL, jfb); }
char *jnl2ext(char *jnl_buff, char *ext_buff) { char *curr, *val_ptr, *ptr, rectype, key_buff[sizeof(gv_key) + MAX_KEY_SZ + 7]; jnl_record *rec; gv_key *key; jnl_string *keystr; int val_extr_len, val_len, rec_len; rec = (jnl_record *)jnl_buff; rectype = rec->prefix.jrec_type; rec_len = rec->prefix.forwptr; if (rec_len != REC_LEN_FROM_SUFFIX(jnl_buff, rec_len)) { assert(FALSE); return ext_buff; } if (!IS_REPLICATED(rectype)) { assert(FALSE); return ext_buff; } curr = ext_buff; if (IS_TUPD(rectype)) { if (FALSE == first_tstart) { GET_SHORTP(curr, &muext_code[MUEXT_TSTART][0]); curr += 2; DELIMIT_CURR; MEMCPY_LIT(curr, ZERO_TIME_DELIM); curr += STR_LIT_LEN(ZERO_TIME_DELIM); curr = (char *)i2asc((uchar_ptr_t)curr, rec->jrec_kill.prefix.tn); DELIMIT_CURR; MEMCPY_LIT(curr, PIDS_DELIM); curr += STR_LIT_LEN(PIDS_DELIM); curr = (char *)i2ascl((uchar_ptr_t)curr, rec->jrec_kill.token_seq.jnl_seqno); *curr++ = '\n'; *curr = '\0'; first_tstart = TRUE; } num_tstarts++; } else if (JRT_TCOM == rectype) { num_tcommits++; if (num_tcommits == num_tstarts) { num_tcommits = num_tstarts = 0; first_tstart = FALSE; GET_SHORTP(curr, &muext_code[MUEXT_TCOMMIT][0]); curr += 2; DELIMIT_CURR; MEMCPY_LIT(curr, ZERO_TIME_DELIM); curr += STR_LIT_LEN(ZERO_TIME_DELIM); curr = (char *)i2asc((uchar_ptr_t)curr, rec->jrec_tcom.prefix.tn); DELIMIT_CURR; MEMCPY_LIT(curr, PIDS_DELIM); curr += STR_LIT_LEN(PIDS_DELIM); curr = (char *)i2ascl((uchar_ptr_t)curr, rec->jrec_tcom.token_seq.jnl_seqno); DELIMIT_CURR; curr = (char *)i2ascl((uchar_ptr_t)curr, rec->jrec_tcom.participants); *curr++ = '\n'; *curr = '\0'; return curr; } return ext_buff; } if (IS_SET(rectype)) GET_SHORTP(curr, &muext_code[MUEXT_SET][0]); else if (IS_KILL(rectype)) GET_SHORTP(curr, &muext_code[MUEXT_KILL][0]); else if (IS_ZKILL(rectype)) GET_SHORTP(curr, &muext_code[MUEXT_ZKILL][0]); else /* if (JRT_NULL == rectype) */ { assert(JRT_NULL == rectype); GET_SHORTP(curr, &muext_code[MUEXT_NULL][0]); } curr += 2; DELIMIT_CURR; MEMCPY_LIT(curr, ZERO_TIME_DELIM); curr += STR_LIT_LEN(ZERO_TIME_DELIM); curr = (char *)i2asc((uchar_ptr_t)curr, rec->jrec_kill.prefix.tn); DELIMIT_CURR; MEMCPY_LIT(curr, PIDS_DELIM); curr += STR_LIT_LEN(PIDS_DELIM); curr = (char *)i2ascl((uchar_ptr_t)curr, rec->jrec_kill.token_seq.jnl_seqno); if (rectype == JRT_NULL) { *curr++ = '\n'; *curr='\0'; return curr; } assert(IS_SET_KILL_ZKILL(rectype)); DELIMIT_CURR; keystr = (jnl_string *)&rec->jrec_kill.mumps_node; ptr = (char *)ROUND_UP((uint4)key_buff, 8); key = (gv_key *)ptr; key->top = MAX_KEY_SZ; key->end = keystr->length; if (key->end > key->top) { assert(FALSE); return ext_buff; } memcpy(key->base, &keystr->text[0], keystr->length); key->base[key->end] = 0; curr = (char *)format_targ_key((uchar_ptr_t)curr, MAX_ZWR_KEY_SZ, key, TRUE); if (IS_SET(rectype)) { *curr++ = '='; val_ptr = &keystr->text[keystr->length]; GET_MSTR_LEN(val_len, val_ptr); val_ptr += sizeof(mstr_len_t); format2zwr((sm_uc_ptr_t)val_ptr, val_len, (uchar_ptr_t)curr, &val_extr_len); curr += val_extr_len; } *curr++ = '\n'; *curr='\0'; return curr; }
char *ext2jnl(char *ptr, jnl_record *rec) { unsigned char *pool_save; char *ret, ch; int keylength, keystate, len, i, reclen, temp_reclen; bool keepgoing; mstr src, des; jnl_record *temp_rec; muextract_type exttype; enum jnl_record_type rectype; jrec_suffix *suffix; ext_stop = ptr + strlen(ptr) + 1; temp_rec = rec; exttype = MUEXTRACT_TYPE(ptr); assert((exttype >= 0) && (exttype < MUEXT_MAX_TYPES)); switch(exttype) { case MUEXT_SET: if (in_tp) { if (0 == num_records) { num_records++; rec->prefix.jrec_type = JRT_TSET; } else rec->prefix.jrec_type = JRT_USET; } else rec->prefix.jrec_type = JRT_SET; break; case MUEXT_KILL: if (in_tp) { if (0 == num_records) { num_records++; rec->prefix.jrec_type = JRT_TKILL; } else rec->prefix.jrec_type = JRT_UKILL; } else rec->prefix.jrec_type = JRT_KILL; break; case MUEXT_ZKILL: if (in_tp) { if (0 == num_records) { num_records++; rec->prefix.jrec_type = JRT_TZKILL; } else rec->prefix.jrec_type = JRT_UZKILL; } else rec->prefix.jrec_type = JRT_ZKILL; break; case MUEXT_TSTART: in_tp = TRUE; num_records = 0; return (char *)rec; break; case MUEXT_TCOMMIT: rec->prefix.jrec_type = JRT_TCOM; in_tp = FALSE; break; case MUEXT_PINI: case MUEXT_PFIN: case MUEXT_EOF: case MUEXT_ZTSTART: case MUEXT_ZTCOMMIT: assert(FALSE); ext_stop = ptr; return (char *)rec; break; case MUEXT_NULL: rec->prefix.jrec_type = JRT_NULL; break; default: assert(FALSE); ext_stop = ptr; return (char *)rec; break; } rectype = rec->prefix.jrec_type; ptr = strtok(ptr, "\\"); /* get the rec-type field */ assert(NULL != ptr); ptr = strtok(NULL, "\\"); /* get the time field */ assert(NULL != ptr); ptr = strtok(NULL, "\\"); /* get the tn field */ assert(NULL != ptr); rec->prefix.tn = asc2i((uchar_ptr_t)ptr, strlen(ptr)); ptr = strtok(NULL, "\\"); /* get the pid field */ assert(NULL != ptr); ptr = strtok(NULL, "\\"); /* get the client pid field */ assert(NULL != ptr); ptr = strtok(NULL, "\\"); /* get the token or jnl_seqno */ assert(NULL != ptr); rec->jrec_null.jnl_seqno = asc2l((uchar_ptr_t)ptr, strlen(ptr)); if (MUEXT_NULL == exttype) { rec->jrec_null.prefix.forwptr = rec->jrec_null.suffix.backptr = NULL_RECLEN; rec->jrec_null.suffix.suffix_code = JNL_REC_SUFFIX_CODE; return ((char_ptr_t)rec) + NULL_RECLEN; } else if (MUEXT_TCOMMIT == exttype) { ptr = strtok(NULL, "\\"); /* get the participants */ ptr = strtok(NULL, "\\"); /* get the jnl_tid */ rec->jrec_tcom.jnl_tid[0] = 0; if (NULL != ptr) strcpy(rec->jrec_tcom.jnl_tid, ptr); num_records = 0; rec->jrec_tcom.prefix.forwptr = rec->jrec_tcom.suffix.backptr = TCOM_RECLEN; rec->jrec_tcom.suffix.suffix_code = JNL_REC_SUFFIX_CODE; return ((char_ptr_t)rec) + TCOM_RECLEN; } ptr = strtok(NULL, "\\"); /* get the key-value and data also */ assert(IS_SET_KILL_ZKILL(rectype)); assert(NULL != ptr); /* this part is lifted from go_load. later think of having a common routine */ len = strlen(ptr); keylength = 0; /* determine length of key */ keystate = 0; keepgoing = TRUE; while((keylength < len) && keepgoing) /* slightly different here from go_load since we can get kill records too */ { ch = *(ptr + keylength); keylength++; switch (keystate) { case 0: /* in global name */ if ('=' == ch) /* end of key */ { keylength--; keepgoing = FALSE; } else if ('(' == ch) /* start of subscripts */ keystate = 1; break; case 1: /* in subscripts area, but out of "..." or $C(...) */ switch (ch) { case ')': /* end of subscripts ==> end of key */ keepgoing = FALSE; break; case '"': /* step into "..." */ keystate = 2; break; case '$': /* step into $C(...) */ assert(('C' == *(ptr + keylength)) || ('c' == *(ptr + keylength))); assert('(' == *(ptr + keylength + 1)); keylength += 2; keystate = 3; break; } break; case 2: /* in "..." */ if ('"' == ch) { switch (*(ptr + keylength)) { case '"': /* "" */ keylength++; break; case '_': /* _$C(...) */ assert('$' == *(ptr + keylength + 1)); assert(('c' == *(ptr + keylength + 2)) || ('C' == *(ptr + keylength + 2))); assert('(' == *(ptr + keylength + 3)); keylength += 4; keystate = 3; break; default: /* step out of "..." */ keystate = 1; } } break; case 3: /* in $C(...) */ if (')' == ch) { if ('_' == *(ptr + keylength)) /* step into "..." */ { assert('"' == *(ptr + keylength + 1)); keylength += 2; keystate = 2; break; } else keystate = 1; /* step out of $C(...) */ } break; default: assert(FALSE); break; } } REPL_DPRINT2("ext2jnl source:KEY=DATA:%s\n", ptr); assert(keylength <= len); str2gvkey_nogvfunc(ptr, keylength, gv_currkey); rec->jrec_kill.mumps_node.length = gv_currkey->end; memcpy(rec->jrec_kill.mumps_node.text, gv_currkey->base, gv_currkey->end); temp_reclen = FIXED_UPD_RECLEN + rec->jrec_kill.mumps_node.length + sizeof(jnl_str_len_t); if (IS_KILL_ZKILL(rectype)) { temp_reclen += JREC_SUFFIX_SIZE; reclen = ROUND_UP2(temp_reclen, JNL_REC_START_BNDRY); memset((char_ptr_t)rec + temp_reclen - JREC_SUFFIX_SIZE, 0, reclen - temp_reclen); suffix = (jrec_suffix *)((char_ptr_t)rec + reclen - JREC_SUFFIX_SIZE); rec->prefix.forwptr = suffix->backptr = reclen; suffix->suffix_code = JNL_REC_SUFFIX_CODE; return (char_ptr_t)rec + reclen; } /* we have to get the data value now */ src.len = len - keylength - 1; src.addr = ptr + (keylength + 1); des.len = 0; des.addr = (char_ptr_t)rec + temp_reclen + sizeof(jnl_str_len_t); REPL_DPRINT3("ext2jnl JNL Format (before zwr2format): src : Len %d :: DATA:%s\n", src.len, src.addr); REPL_DPRINT3("ext2jnl JNL Format (before zwr2format): des : Len %d :: DATA:%s\n", des.len, des.addr); if (!zwr2format(&src, &des)) { assert(FALSE); return (char_ptr_t)rec; } REPL_DPRINT3("ext2jnl JNL Format : src : Len %d :: DATA:%s\n", src.len, src.addr); REPL_DPRINT3("ext2jnl JNL Format : des : Len %d :: DATA:%s\n", des.len, des.addr); PUT_MSTR_LEN((char_ptr_t)rec + temp_reclen, des.len); temp_reclen += sizeof(jnl_str_len_t) + des.len + JREC_SUFFIX_SIZE; reclen = ROUND_UP2(temp_reclen, JNL_REC_START_BNDRY); memset((char_ptr_t)rec + temp_reclen - JREC_SUFFIX_SIZE, 0, reclen - temp_reclen); suffix = (jrec_suffix *)((char_ptr_t)rec + reclen - JREC_SUFFIX_SIZE); rec->prefix.forwptr = suffix->backptr = reclen; suffix->suffix_code = JNL_REC_SUFFIX_CODE; return (char_ptr_t)rec + reclen; }
int jnl_v11tov15(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, uint4 *conv_len, uint4 conv_bufsiz) { /* Convert a transaction from jnl version 11 (V4.2-002) to 15 (V.4.4-002) */ unsigned char *jb, *cb, *cstart, *jstart, rectype; int status, reclen; unsigned short key_len; unsigned int long_data_len, jlen, total_data, nzeros, conv_reclen, clen_without_sfx, total_key; jrec_prefix prefix; jrec_suffix suffix; seq_num jsno; jb = jnl_buff; cb = conv_buff; status = SS_NORMAL; jlen = *jnl_len; while (0 < jlen) { if (0 < (reclen = v11_jnl_record_length((jnl_record *)jb, jlen))) { if (reclen <= jlen) { rectype = REF_CHAR(jb + V11_JREC_TYPE_OFFSET); total_key = total_data = 0; assert(IS_REPLICATED(rectype)); if (IS_ZTP(rectype)) GTMASSERT; /* ZTP not supported */ if (IS_SET_KILL_ZKILL(rectype)) { GET_USHORT(key_len, jb + V11_JREC_PREFIX_SIZE + v11_jnl_fixed_size[rectype]); total_key = key_len + sizeof(unsigned short); if (IS_SET(rectype)) { GET_MSTR_LEN(long_data_len, jb + V11_JREC_PREFIX_SIZE + v11_jnl_fixed_size[rectype] + total_key); total_data = long_data_len + sizeof(mstr_len_t); } conv_reclen = JREC_PREFIX_SIZE + FIXED_UPD_RECLEN + total_key + total_data + JREC_SUFFIX_SIZE; conv_reclen = ROUND_UP2(conv_reclen, JNL_REC_START_BNDRY); } else if (IS_COM(rectype)) conv_reclen = JREC_PREFIX_SIZE + TCOM_RECLEN + JREC_SUFFIX_SIZE; clen_without_sfx = conv_reclen - JREC_SUFFIX_SIZE; if (cb - conv_buff + conv_reclen > conv_bufsiz) { repl_errno = EREPL_INTLFILTER_NOSPC; status = -1; break; } cstart = cb; jstart = jb; prefix.jrec_type = rectype; suffix.backptr = prefix.forwptr = conv_reclen; prefix.pini_addr = 0; prefix.time = 0; prefix.tn = 0; suffix.suffix_code = JNL_REC_SUFFIX_CODE; memcpy(cb, (unsigned char*)&prefix, JREC_PREFIX_SIZE); cb += JREC_PREFIX_SIZE; memcpy(cb, jb + V11_JREC_PREFIX_SIZE + V11_JNL_SEQNO_OFFSET, sizeof(seq_num)); cb += sizeof(seq_num); if (IS_SET_KILL_ZKILL(rectype)) { PUT_JNL_STR_LEN(cb, key_len); jb += (V11_JREC_PREFIX_SIZE + V11_MUMPS_NODE_OFFSET + sizeof(unsigned short)); if (IS_FENCED(rectype)) jb += TP_TOKEN_TID_SIZE; cb += sizeof(jnl_str_len_t); memcpy(cb, jb, key_len); cb += key_len; jb += key_len; if (IS_SET(rectype)) { PUT_MSTR_LEN(cb, long_data_len); cb += sizeof(mstr_len_t); jb += sizeof(mstr_len_t); memcpy(cb, jb, long_data_len); cb += long_data_len; } } else if (IS_COM(rectype)) { assert(JRT_TCOM == rectype); memset(cb, 0, TID_STR_SIZE); cb += TID_STR_SIZE; memcpy(cb, jb + V11_JREC_PREFIX_SIZE + V11_TCOM_PARTICIPANTS_OFFSET, sizeof(uint4)); cb += sizeof(uint4); } else assert(FALSE); nzeros = (cstart + clen_without_sfx - cb); if (nzeros > 0) { memset(cb, 0, nzeros); cb += nzeros; } jb = jstart + reclen; memcpy(cb, (unsigned char*)&suffix, JREC_SUFFIX_SIZE); cb += JREC_SUFFIX_SIZE; assert(cb == cstart + conv_reclen); jlen -= reclen; continue; } repl_errno = EREPL_INTLFILTER_INCMPLREC; status = -1; break; } repl_errno = EREPL_INTLFILTER_BADREC; status = -1; break; } assert(0 == jlen || -1 == status); *jnl_len = jb - jnl_buff; *conv_len = cb - conv_buff; return(status); }
void jnl_format(jnl_format_buffer *jfb) { enum jnl_record_type rectype; sgmnt_addrs *csa; uint4 align_fill_size, jrec_size, tmp_jrec_size; int subcode; jnl_action *ja; char *local_buffer; jnl_str_len_t keystrlen; mstr_len_t valstrlen; csa = &FILE_INFO(gv_cur_region)->s_addrs; if (jnl_fence_ctl.level == 0 && dollar_tlevel == 0) { /* Non-TP */ subcode = 0; tmp_jrec_size = FIXED_UPD_RECLEN + JREC_SUFFIX_SIZE; } else { if (NULL == csa->next_fenced) { /* F (or T) */ subcode = 1; csa->next_fenced = jnl_fence_ctl.fence_list; jnl_fence_ctl.fence_list = csa; } else /* G (or U) */ subcode = 3; if (0 != dollar_tlevel) { /* TP */ ++subcode; tmp_jrec_size = FIXED_UPD_RECLEN + JREC_SUFFIX_SIZE; } else tmp_jrec_size = FIXED_ZTP_UPD_RECLEN + JREC_SUFFIX_SIZE; } ja = &(jfb->ja); rectype = jnl_opcode[ja->operation][subcode]; assert(rectype > JRT_BAD && rectype < JRT_RECTYPES); assert(IS_SET_KILL_ZKILL(rectype)); /* Compute actual record length */ assert(NULL != ja->key); keystrlen = ja->key->end; tmp_jrec_size += keystrlen + sizeof(jnl_str_len_t); if (JNL_SET == ja->operation) { assert(NULL != ja->val); valstrlen = ja->val->str.len; tmp_jrec_size += valstrlen + sizeof(mstr_len_t); } jrec_size = ROUND_UP2(tmp_jrec_size, JNL_REC_START_BNDRY); align_fill_size = jrec_size - tmp_jrec_size; /* For JNL_REC_START_BNDRY alignment */ if (dollar_tlevel) { assert((1 << JFB_ELE_SIZE_IN_BITS) == JNL_REC_START_BNDRY); assert(JFB_ELE_SIZE == JNL_REC_START_BNDRY); jfb->buff = (char *)get_new_element(sgm_info_ptr->format_buff_list, jrec_size >> JFB_ELE_SIZE_IN_BITS); /* assume an align record will be written while computing maximum jnl-rec size requirements */ sgm_info_ptr->total_jnl_rec_size += jrec_size + MIN_ALIGN_RECLEN; } /* else if (0 == dollar_tlevel) jfb->buff already malloced in gvcst_init */ jfb->record_size = jrec_size; jfb->rectype = rectype; /* PREFIX */ ((jrec_prefix *)jfb->buff)->jrec_type = rectype; ((jrec_prefix *)jfb->buff)->forwptr = jrec_size; if (IS_ZTP(rectype)) local_buffer = jfb->buff + FIXED_ZTP_UPD_RECLEN; else local_buffer = jfb->buff + FIXED_UPD_RECLEN; *(jnl_str_len_t *)local_buffer = keystrlen; /* direct assignment for already aligned address */ local_buffer += sizeof(jnl_str_len_t); memcpy(local_buffer, (uchar_ptr_t)ja->key->base, keystrlen); local_buffer += keystrlen; if (JNL_SET == ja->operation) { PUT_MSTR_LEN(local_buffer, valstrlen); /* SET command's data may not be aligned */ local_buffer += sizeof(jnl_str_len_t); memcpy(local_buffer, (uchar_ptr_t)ja->val->str.addr, valstrlen); local_buffer += valstrlen; } if (0 != align_fill_size) { memset(local_buffer, 0, align_fill_size); local_buffer += align_fill_size; } assert(0 == ((uint4)local_buffer % sizeof(jrec_suffix))); /* SUFFIX */ ((jrec_suffix *)local_buffer)->backptr = jrec_size; ((jrec_suffix *)local_buffer)->suffix_code = JNL_REC_SUFFIX_CODE; }
int jnl_v15tov16(uchar_ptr_t jnl_buff, uint4 *jnl_len, uchar_ptr_t conv_buff, uint4 *conv_len, uint4 conv_bufsiz) { unsigned char *jb, *cb, *cstart, *jstart, *ptr; enum jnl_record_type rectype; int status, reclen, conv_reclen; uint4 jlen; jrec_prefix *prefix; jb = jnl_buff; cb = conv_buff; status = SS_NORMAL; jlen = *jnl_len; assert(0 == ((UINTPTR_T)jb % sizeof(uint4))); while (JREC_PREFIX_SIZE <= jlen) { assert(0 == ((UINTPTR_T)jb % sizeof(uint4))); prefix = (jrec_prefix *)jb; rectype = (enum jnl_record_type)prefix->jrec_type; cstart = cb; jstart = jb; if (0 != (reclen = prefix->forwptr)) { if (reclen <= jlen) { assert(IS_REPLICATED(rectype)); conv_reclen = prefix->forwptr ; if (cb - conv_buff + conv_reclen > conv_bufsiz) { repl_errno = EREPL_INTLFILTER_NOSPC; status = -1; break; } memcpy(cb, jb, reclen); if (IS_SET_KILL_ZKILL(rectype) && null_subs_xform) { ptr = cb + FIXED_UPD_RECLEN + sizeof(jnl_str_len_t); /* Prior to V16, GT.M supports only GTM NULL collation */ assert(GTMNULL_TO_STDNULL_COLL == null_subs_xform); GTM2STDNULLCOLL(ptr, *((jnl_str_len_t *)(cb + FIXED_UPD_RECLEN))); } cb = cb + reclen ; jb = jb + reclen ; assert(cb == cstart + conv_reclen); assert(jb == jstart + reclen); jlen -= reclen; continue; } repl_errno = EREPL_INTLFILTER_INCMPLREC; assert(FALSE); status = -1; break; } repl_errno = EREPL_INTLFILTER_BADREC; assert(FALSE); status = -1; break; } if ((-1 != status) && (0 != jlen)) { repl_errno = EREPL_INTLFILTER_INCMPLREC; assert(FALSE); status = -1; } assert(0 == jlen || -1 == status); *jnl_len = (uint4)(jb - jnl_buff); *conv_len = (uint4)(cb - conv_buff); return(status); }