/// <summary> /// Сохранить данные на диск. /// </summary> /// <param name="record">Массив байт.</param> public void Save(DataRecord record) { lock (_createDataPageLock) { var recordId = ++_currentDataRecordId; record.SetDataRecordId(recordId); var data = record.GetBytes(); var dataLength = data.Length; // пишем последовательно, поэтому получаем всегда для записи последнюю страницу. var currentDataPage = GetLastPage(); // если на текущей странице хватает свободного места для данных, указанной длины if (currentDataPage.HasEnoughSpaceFor(dataLength)) { // то пишем в текущую страницу. currentDataPage.TrySaveData(recordId, data, out var dataOffset); // добавляем в индекс _dataRecordIndexStorage.AddToIndex(new DataRecordIndexPointer( recordId, currentDataPage.PageId, dataOffset, dataLength ) ); return; } // если же места не хватило на одной странице, то уже пишем в несколько: var dataRecordIndexPointers = new List <DataRecordIndexPointer>(); var writtenBytes = 0; var dataSpan = data.AsSpan(); // узнаем, сколько можно записать в текущую страницу: var freeSpaceLength = currentDataPage.GetFreeSpaceFor(dataSpan.Length); // если оказалось что мы что-то можем записать. if (freeSpaceLength > 0) { // то срезаем кусок данных var firstWrite = dataSpan.Slice(0, freeSpaceLength).ToArray(); // и заполним оставшееся место в текущей странице if (currentDataPage.TrySaveData(recordId, firstWrite, out var offset)) { dataRecordIndexPointers.Add(new DataRecordIndexPointer( recordId, currentDataPage.PageId, offset, firstWrite.Length ) ); } writtenBytes += freeSpaceLength; } // и до тех пор, пока все не будет записано... while (writtenBytes < dataLength) { // создадём новую страницу. currentDataPage = CreateNew(); // получим кол-во байт, которое можно записать в текущую страницу. var bytesToWrite = currentDataPage.GetFreeSpaceFor(dataLength - writtenBytes); Debug.Assert(bytesToWrite != 0); // создаем разрез для записи. var slice = dataSpan.Slice(writtenBytes, bytesToWrite).ToArray(); // сохраняем. currentDataPage.TrySaveData(recordId, slice, out var offset); dataRecordIndexPointers.Add(new DataRecordIndexPointer( recordId, currentDataPage.PageId, offset, slice.Length ) ); writtenBytes += slice.Length; } // Первый индекс сделаем основным, остальные как дополнения. var index = dataRecordIndexPointers.First(); _dataRecordIndexStorage.AddToIndex(new DataRecordIndexPointer( index.DataRecordId, index.DataPageNumber, index.Offset, index.Length, dataRecordIndexPointers.Skip(1).ToArray() ) ); } }