EbUint8 * EbRecord::LocateEncodedField(EbUint32 fid) { // check fid EB_ASSERT(fid < NumberOfFields()); EB_ASSERT(_pRecordData != NULL); EbUint8 * field = _pRecordData + PADDED_SIZE(NumberOfFields()*sizeof(EncodedFieldSize), 4); for (EbUint32 i=0; i< fid; i++) { field += PADDED_SIZE(((EncodedFieldSize*)_pRecordData)[i], 4); } return field; }
/*********************************************************************** * void Ebase::DeleteRecord() *********************************************************************** */ void Ebase::DeleteRecord(EbRecord *pRecord) { EbUint32 i; // check record validity if (pRecord == NULL || pRecord->_pEbase != this) { EB_ASSERT (0 == "EBE_INVALID_RECORD"); } // check if it is a new record status if (pRecord->_pRecordData == NULL) { EB_ASSERT(pRecord->_handle == EB_INVALID_HANDLE); EB_ASSERT(*((EbInt32*)pRecord->_lField[RECORD_ID_INDEX]._decodedData) == NEW_RECORD_ID); // free memory space occupied by the record delete pRecord; return; } // this is an existing record EB_ASSERT(pRecord->_handle != EB_INVALID_HANDLE); EB_ASSERT(pRecord->_lField[RECORD_ID_INDEX]._decodedData == NULL || *((EbInt32*)pRecord->_lField[RECORD_ID_INDEX]._decodedData) != NEW_RECORD_ID); // we need to free the file space it occupies // free file space occupied by field data EbUint8* pField = pRecord->_pRecordData + PADDED_SIZE(_dbDef->NumberOfFields()*sizeof(EncodedFieldSize), 4); // EncodedFieldSize *& fieldSize = pRecord->_pRecordData; EncodedFieldSize * pFieldSize = (EncodedFieldSize*)pRecord->_pRecordData; for(i=0; i< _dbDef->NumberOfFields(); i++) { // _lpDataDriver[i]->FreeEncodedData(pField, fieldSize[i],_file); // pField += PADDED_SIZE(fieldSize[i], 4); _lpDataDriver[i]->FreeEncodedData(pField, pFieldSize[i],_file); pField += PADDED_SIZE(pFieldSize[i], 4); } // remove from the index entry array // for(i=0; i< _indexDefWrapper->Size(); i++) { _Int32IndexEntry->GetHandleArray()->Delete( _Int32IndexEntry->GetHandleArray()->Find(pRecord->_handle)); // } // free the file space occupied by the record _file->DeleteData(pRecord->_handle); // adjust ebase state _hdr._numRecords --; // save index entries SaveHeader(); SaveIndexEntries(); // free the memory delete pRecord; }
void Ebase::AddNewRecord(EbRecord *pRecord) { EB_ASSERT(_Int32IndexEntry->IsValid() == EB_TRUE); EbUint32 i; EbUint32 numFinishedFields, numFinishedIndices; EbErrorEnum error; // contain the encoded record data for the new record EbUint8 * pNewRecordData; // handle used to store the new record EbDataHandle newRecordHandle; EbUint32 numFields = pRecord->_pEbase->_dbDef->NumberOfFields(); EbUint32 newRecordSize; // check if pRecord is created by this ebase if (pRecord->_pEbase != this) { EB_ASSERT (0 == "EBE_INVALID_RECORD"); } // check if it is a new record EbInt32 *pRecordID = (EbInt32*)pRecord->_lField[RECORD_ID_INDEX]._decodedData; EB_ASSERT(*pRecordID == NEW_RECORD_ID); // set the record id *pRecordID = _hdr._nextRecordID; // calculate the new record size newRecordSize = PADDED_SIZE(numFields*sizeof(EncodedFieldSize), 4); for (i=0; i< numFields; i++) { EbUint32 size; DataDriver * pDriver = pRecord->_pEbase->_lpDataDriver[i]; size = pDriver->EncodedDataSize(pRecord->_lField[i]._decodedData); EB_ASSERT(size <= EB_MAX_ENCODED_FIELD_SIZE); newRecordSize += PADDED_SIZE(size, 4); } // (res alloc #1) allocate memory to hold the new record pNewRecordData = new EbUint8[newRecordSize]; if (pNewRecordData == NULL) { error = EBE_OUT_OF_MEMORY; goto bailout; } // (res alloc #2) allocate file space for the record // For existing record, we will re-use the same space if the new // record size is no greater than the old record size. newRecordHandle = _file->NewData(newRecordSize); if (newRecordHandle == EB_INVALID_HANDLE) { error = EBE_OUT_OF_FILE_SPACE; goto bailout_1; } // // (res alloc #3) encode data. Some file space may be allocated in this // step. // { // get the start of the field data area in the record data EbUint8 *pNewField = pNewRecordData + PADDED_SIZE(numFields*sizeof(EncodedFieldSize), 4); // EncodedFieldSize *& newEncodedFieldSize = pNewRecordData; EncodedFieldSize * pNewEncodedFieldSize = (EncodedFieldSize*)pNewRecordData; for (i=0; i< numFields; i++) { DataDriver * pDriver = pRecord->_pEbase->_lpDataDriver[i]; EbUint32 size; pDriver->Encode(pRecord->_lField[i]._decodedData, pNewField, size, EB_FALSE, _file); EB_ASSERT(size <= EB_MAX_ENCODED_FIELD_SIZE); // newEncodedFieldSize[i] = (EncodedFieldSize)size; pNewEncodedFieldSize[i] = (EncodedFieldSize)size; // advance pField pNewField += PADDED_SIZE(size, 4); } } // for later error recovery numFinishedFields = numFields; // // (res alloc #4) // We sort the records. For the new record case, we need to expand // index entry arrays. // // (res alloc #4_1) sort record id index - an optimization // A new record is always the last in the record ID index. numFinishedIndices = 0; if (_Int32IndexEntry->GetHandleArray()->Append(newRecordHandle) == EB_FAILURE) { error = EBE_OUT_OF_MEMORY; goto bailout_3; } // // (res alloc #4_2) for other indices numFinishedIndices = 1; //_Int32IndexEntry->IsValid() == EB_TRUE ? 1 : 0; // // (res alloc #5) reserve file space for the expanded index entry arrays // if (_Int32IndexEntry->ReserveSpace(*_file, _hdr._indexEntryHandle) == EB_FAILURE) { error = EBE_OUT_OF_FILE_SPACE; goto bailout_4; } // commit the record _file->WriteData(newRecordHandle, pNewRecordData); // adjust record state pRecord->_handle = newRecordHandle; pRecord->_pRecordData = pNewRecordData; for (i=0; i< numFields; i++) { EB_ASSERT(pRecord->_lField[i]._changed == EB_TRUE); pRecord->_lField[i]._changed = EB_FALSE; pRecord->_lField[i]._decoded = EB_TRUE; } // adjust ebase state _hdr._nextRecordID++; _hdr._numRecords++; // save & return // NOTE : we don't have to save index entries here since they can // be recovered. But right now, we don't provide recovery and // we want to be a little convservative. SaveHeader(); SaveIndexEntries(); return; bailout_4: //for (i=0; i< numFinishedIndices; i++) { if (numFinishedIndices == 1) { EbInt32 pos = _Int32IndexEntry->GetHandleArray()->Find(pRecord->_handle); EB_ASSERT(pos >= 0); _Int32IndexEntry->GetHandleArray()->Delete((EbUint32)pos); } // we just shrunk the array. space reservation should be OK EB_VERIFY(_Int32IndexEntry->ReserveSpace(*_file, _hdr._indexEntryHandle), == EB_SUCCESS); bailout_3: // free resources allocated during data encoding { EbUint8 *pNewField = pNewRecordData + PADDED_SIZE(numFields*sizeof(EncodedFieldSize), 4); // EncodedFieldSize *& newEncodedFieldSize = pNewRecordData; EncodedFieldSize * pNewEncodedFieldSize = (EncodedFieldSize*)pNewRecordData; for (EbUint32 j=0; j< numFinishedFields; j++) { if (pRecord->_lField[i]._changed == EB_TRUE) { DataDriver * pDriver = pRecord->_pEbase->_lpDataDriver[i]; pDriver->FreeEncodedData(pNewField, // newEncodedFieldSize[i], pNewEncodedFieldSize[i], _file); } // pNewField += PADDED_SIZE(newEncodedFieldSize[i], 4); pNewField += PADDED_SIZE(pNewEncodedFieldSize[i], 4); } } /*bailout_2:*/ _file->DeleteData(newRecordHandle); bailout_1: delete[] pNewRecordData; bailout: { EbError e(error); printf ("error: %s\n\n", e.GetStringName ()); EB_ASSERT (0 == 1); } }
// // Modify an existing record : // 1. calculate the new record size // 2. allocate memory to hold the record // 3. if the new size is bigger, we need to allocate a new data handle // 4. encode all modified field data // 5. re-sort indcies (no allocation is needed) // 6. adjust record states, free old resources // void Ebase::ModifyRecord(EbRecord *pRecord) { // check the record is valid and is an existing record EB_ASSERT(pRecord != NULL); EB_ASSERT(pRecord->_lField[RECORD_ID_INDEX]._changed == EB_FALSE); EB_ASSERT(pRecord->_lField[RECORD_ID_INDEX]._decoded == EB_FALSE || *(EbInt32*)pRecord->_lField[RECORD_ID_INDEX]._decodedData != NEW_RECORD_ID); EB_ASSERT(pRecord->_handle != EB_INVALID_HANDLE); // check if pRecord is created by this ebase if (pRecord->_pEbase != this) { EB_ASSERT (0 == "EBE_INVALID_RECORD"); } // local variables EbErrorEnum error; EbUint32 newRecordSize, oldRecordSize; EbUint8 * pNewRecordData; EbDataHandle newRecordHandle; EbUint32 numFinishedFields; EbUint32 i; EbUint32 numFields = _dbDef->NumberOfFields(); // EncodedFieldSize *& oldFieldSize = pRecord->_pRecordData; EncodedFieldSize ** ppOldFieldSize = (EncodedFieldSize **)&(pRecord->_pRecordData); // get the old record size oldRecordSize = _file->DataSize(pRecord->_handle); // calculate the new record size newRecordSize = PADDED_SIZE(numFields*sizeof(EncodedFieldSize), 4); for (i=0; i< numFields; i++) { DataDriver * pDriver = pRecord->_pEbase->_lpDataDriver[i]; if (pRecord->_lField[i]._changed == EB_TRUE) { // this is new data EbUint32 size = pDriver->EncodedDataSize(pRecord->_lField[i]._decodedData); EB_ASSERT(size <= EB_MAX_ENCODED_FIELD_SIZE); newRecordSize += PADDED_SIZE(size, 4); } else { // this the old data // newRecordSize += PADDED_SIZE(oldFieldSize[i], 4); newRecordSize += PADDED_SIZE((*ppOldFieldSize)[i], 4); } } // (res alloc #1) allocate memory to hold the new record pNewRecordData = new EbUint8[newRecordSize]; if (pNewRecordData == NULL) { error = EBE_OUT_OF_MEMORY; goto bailout; } // (res alloc #2) allocate file space for the record // For existing record, we will re-use the same space if the new // record size is no greater than the old record size. if (newRecordSize > oldRecordSize) { newRecordHandle = _file->NewData(newRecordSize); if (newRecordHandle == EB_INVALID_HANDLE) { error = EBE_OUT_OF_FILE_SPACE; goto bailout_1; } } else { newRecordHandle = pRecord->_handle; } // (res alloc #3) Build the new record and encode any modified field // File space may be allocated when encoding field data { EbUint8 *pOldField = pRecord->_pRecordData + PADDED_SIZE(numFields*sizeof(EncodedFieldSize), 4); EbUint8 *pNewField = pNewRecordData + PADDED_SIZE(numFields*sizeof(EncodedFieldSize), 4); // EncodedFieldSize *& newFieldSize = pNewRecordData; EncodedFieldSize *pNewFieldSize = (EncodedFieldSize*)pNewRecordData; for (i=0; i< numFields; i++) { numFinishedFields = i; if (pRecord->_lField[i]._changed == EB_TRUE) { // this is new data DataDriver * pDriver = pRecord->_pEbase->_lpDataDriver[i]; EbUint32 size; pDriver->Encode(pRecord->_lField[i]._decodedData, pNewField, size, EB_FALSE, _file); EB_ASSERT(size <= EB_MAX_ENCODED_FIELD_SIZE); pNewFieldSize[i] = (EncodedFieldSize)size; // advance pField pNewField += PADDED_SIZE(size, 4); // pOldField += PADDED_SIZE(oldFieldSize[i], 4); pOldField += PADDED_SIZE((*ppOldFieldSize)[i], 4); } else { // this is the old data. We just copy it. // memcpy(pNewField, pOldField, oldFieldSize[i]); // newFieldSize[i] = oldFieldSize[i]; memcpy(pNewField, pOldField, (*ppOldFieldSize)[i]); pNewFieldSize[i] = (*ppOldFieldSize)[i]; // advance pField // pNewField += PADDED_SIZE(oldFieldSize[i], 4); // pOldField += PADDED_SIZE(oldFieldSize[i], 4); pNewField += PADDED_SIZE((*ppOldFieldSize)[i], 4); pOldField += PADDED_SIZE((*ppOldFieldSize)[i], 4); } } } numFinishedFields = numFields; // we still need to replace the old handle with // possibly a new handle { EbUint32 oldPos_0 = _Int32IndexEntry->GetHandleArray()->Find(pRecord->_handle); _Int32IndexEntry->Get(oldPos_0) = newRecordHandle; } // sort indices // 1. find the current position of the record // 2. find the new position of the record with modified fields // 3. move from old position to the new position. // // this step does not have any bailout handling. so no step after // this can fail (for now). // commit writing the record. This may make the original // record non-retrievable. So nothing after this step // should cause failure. _file->WriteData(newRecordHandle, pNewRecordData); // free old resources { EbUint8 *pField = pRecord->_pRecordData + PADDED_SIZE(numFields*sizeof(EncodedFieldSize), 4); for (i=0; i< numFields; i++) { if (pRecord->_lField[i]._changed == EB_TRUE) { DataDriver * pDriver = pRecord->_pEbase->_lpDataDriver[i]; pDriver->FreeEncodedData(pField, // oldFieldSize[i], (*ppOldFieldSize)[i], _file); } // pField += PADDED_SIZE(oldFieldSize[i], 4); pField += PADDED_SIZE((*ppOldFieldSize)[i], 4); } } if (pRecord->_handle != newRecordHandle) { _file->DeleteData(pRecord->_handle); } delete[] pRecord->_pRecordData; // adjust record state pRecord->_handle = newRecordHandle; pRecord->_pRecordData = pNewRecordData; for (i=0; i< numFields; i++) { if(pRecord->_lField[i]._changed == EB_TRUE) { pRecord->_lField[i]._changed = EB_FALSE; pRecord->_lField[i]._decoded = EB_TRUE; } } // save index entries and return SaveHeader(); SaveIndexEntries(); return; //bailout_3: // free resources allocated during data encoding { EbUint8 *pNewField = pNewRecordData + PADDED_SIZE(numFields*sizeof(EncodedFieldSize), 4); // EncodedFieldSize *& newEncodedFieldSize = pNewRecordData; EncodedFieldSize *pNewEncodedFieldSize = (EncodedFieldSize*)pNewRecordData; for (EbUint32 j=0; j< numFinishedFields; j++) { if (pRecord->_lField[i]._changed == EB_TRUE) { DataDriver * pDriver = pRecord->_pEbase->_lpDataDriver[i]; pDriver->FreeEncodedData(pNewField, // newEncodedFieldSize[i], pNewEncodedFieldSize[i], _file); } // pNewField += PADDED_SIZE(newEncodedFieldSize[i], 4); pNewField += PADDED_SIZE(pNewEncodedFieldSize[i], 4); } } /*bailout_2: */ if (newRecordSize > oldRecordSize) { EB_ASSERT(newRecordHandle != pRecord->_handle); _file->DeleteData(newRecordHandle); } bailout_1: delete[] pNewRecordData; bailout: EB_ASSERT (0 == "EBE_OUT_OF_MEMORY"); }
/* * MPALMOSTSAFE */ int sys_ogetdirentries(struct ogetdirentries_args *uap) { int error, bytes_transfered; char *buf, *outbuf; size_t len; struct dirent *ndp; struct odirent *destdp; long base; if (uap->count > 16384) len = 16384; else len = uap->count; buf = kmalloc(len, M_TEMP, M_WAITOK); get_mplock(); error = kern_getdirentries(uap->fd, buf, len, &base, &bytes_transfered, UIO_SYSSPACE); rel_mplock(); if (error) { kfree(buf, M_TEMP); return(error); } ndp = (struct dirent *)buf; outbuf = uap->buf; destdp = kmalloc(PADDED_SIZE(MAX_NAMELEN), M_TEMP, M_WAITOK); for (; (char *)ndp < buf + bytes_transfered; ndp = _DIRENT_NEXT(ndp)) { if ((char *)_DIRENT_NEXT(ndp) > buf + bytes_transfered) break; if (ndp->d_namlen > MAX_NAMELEN) continue; destdp->od_fileno = ndp->d_ino; #if BYTE_ORDER == LITTLE_ENDIAN destdp->od_type = ndp->d_namlen; destdp->od_namlen = ndp->d_type; #else destdp->od_type = ndp->d_type; destdp->od_namlen = ndp->d_namlen; #endif destdp->od_reclen = PADDED_SIZE(destdp->od_namlen); if (destdp->od_reclen > len) break; /* XXX can not happen */ bcopy(ndp->d_name, destdp->od_name, destdp->od_namlen); bzero(destdp->od_name + destdp->od_namlen, PADDED_SIZE(destdp->od_namlen) - sizeof(*destdp) - destdp->od_namlen); error = copyout(destdp, outbuf, PADDED_SIZE(destdp->od_namlen)); if (error) break; outbuf += PADDED_SIZE(destdp->od_namlen); len -= PADDED_SIZE(destdp->od_namlen); } kfree(destdp, M_TEMP); kfree(buf, M_TEMP); uap->sysmsg_iresult = (int)(outbuf - uap->buf); return (0); }