/// <summary> /// /// </summary> /// <param name="offset"></param> /// <param name="data"></param> public void Table_WriteByOffset(long offset, byte[] data) { /* Emulation of the direct save without random cache */ //lock (lock_fs) //{ // FlushSequentialBuffer(); // _fsData.Position = offset; // _fsData.Write(data, 0, data.Length); //} //Console.WriteLine("yeah"); //return; /******************************************************/ //DB RULE1. We cant update and go out of the end of file //!! ALL throw new Exception must be taken away after testS //!! This is a cutted implementation for DBreeze we dont take care buffer elements overlapping (start+len U some elements -> should be not possible) //overwriting partly file and partly sequential buffer is not allowed if (data == null || data.Length == 0) { throw new Exception("FSR.WriteByOffset: data == null || data.Length == 0"); } lock (lock_fs) { if (offset >= _fsData.Length) { //Overwriting sequential buffer _seqBuf.Write_ByOffset(Convert.ToInt32(offset - _fsData.Length), data); return; } if (offset < _fsData.Length && offset + data.Length > _fsData.Length) { throw new Exception("FSR.WriteByOffset: offset < _fsData.Length && offset + data.Length > _fsData.Length"); } if (offset + data.Length > (_fsData.Length + _seqBuf.EOF)) { //DB RULE1. We cant update and go out of the end of file. Only if we write into empty file root in the beginning throw new Exception("FSR.WriteByOffset: offset + data.Length > (_fsData.Length + seqEOF)"); } byte[] inBuf = null; if (_randBuf.TryGetValue(offset, out inBuf)) { if (inBuf.Length != data.Length) { //OLD solution //it means we overwrite second time the same position with different length of data - what is not allowed //throw new Exception("FSR.WriteByOffset: inBuf.Length != data.Length"); //Solution from 20140425 //we just overwrite offset value with the new data } //setting new value for such offset _randBuf[offset] = data; } else { //We put data to the buffer first and flush it if buffer > allowed space. We dont take care if data is bigger then buffer. //In any case first we put it to the buffer _randBuf.Add(offset, data); usedBufferSize += data.Length; } //if we are able to store data into buffer lets do it if (usedBufferSize >= maxRandomBufferSize || _randBuf.Count() > maxRandomElementsCount) { FlushRandomBuffer(); } } }
/// <summary> /// Is called only from lock_fs and must be finished by calling NET_Flush /// </summary> /// <param name="commit"></param> void FlushRandomBuffer() { if (_randBuf.Count() == 0) { return; } //First we write all data into rollback file and helper, calling flush on rollback //then updating data of data file but dont call update //clearing random buffer //Creating rollback header byte[] offset = null; byte[] btRoll = null; bool flushRollback = false; //first loop for saving rollback data foreach (var de in _randBuf.OrderBy(r => r.Key)) //sorting can mean nothing here, only takes extra time { offset = ((ulong)de.Key).To_8_bytes_array_BigEndian().Substring(8 - DefaultPointerLen, DefaultPointerLen); if (_rollbackCache.ContainsKey(de.Key)) { continue; } //Reading from dataFile values which must be rolled back btRoll = new byte[de.Value.Length]; _fsData.Write_ByOffset((int)de.Key, ref btRoll); //Forming protocol for rollback btRoll = new byte[] { 1 } .ConcatMany( offset, ((uint)btRoll.Length).To_4_bytes_array_BigEndian(), btRoll ); //Writing rollback _fsRollback.Write_ByOffset((int)eofRollback, ref btRoll); _rollbackCache.Add(de.Key, new r { o = eofRollback + 1 + offset.Length + 4, l = de.Value.Length }); //10 is size of protocol data //increasing eof rollback file eofRollback += btRoll.Length; flushRollback = true; } if (flushRollback) { //Writing into helper btRoll = eofRollback.To_8_bytes_array_BigEndian(); _fsRollbackHelper.Write_ByOffset(0, ref btRoll); //Flushing rollback and rollback helper } //second loop for saving data foreach (var de in _randBuf.OrderBy(r => r.Key)) //sorting can mean nothing here, only takes extra time { btRoll = de.Value; _fsData.Write_ByOffset((int)de.Key, ref btRoll); } //No flush of data file, it will be done on Flush() _randBuf.Clear(); usedBufferSize = 0; }