Большие отчёты

Обсуждение Stimulsoft Reports.NET
TVV
Сообщения: 27
Зарегистрирован: 08 сен 2006, 15:07

Большие отчёты

Сообщение TVV »

Добрый день.

Столкнулись с проблемой нехватки памяти при генерации(и конвертации в PDF) нескольких больших(болле 500 страниц) отчётов.

Поискал подобные вопросы и нашел вот что :
"есть возможность кэшировать отчеты. В этом случае только небольшая часть отчета находится в памяти, все остальное выгружается в спецаильный кэш. Скорость построения падает не сильно, есть небольшие ограничения, но потребеление памяти радикально меньше. Т.е. можно построить очень большие отчеты, при этом в памяти будет храниться только 20-30 страниц (это настраевается) отчета. Включить кэширование можно при помощи свойства ReportCacheMode отчета."

Ну, вот у меня и возник ряд вопросов.

1. "есть небольшие ограничения". А можно подробнее? У нас документы(отчёты) генерируются и конвертируются в PDF параллельно в нескольких процессах, и в каждом ещё несколько потоков. Не возникнет ли конфликтов при кэшировании?

2. Подскажите наилучшую стратегию. Чаще всего генерится много маленьких документов, но иногда "попадаются" очень большие. Т.е., скорее всего, нужно перед генерацией(рендерингом) устанавливать ReportCacheMode в нужное значение. Как лучше это сделать? Анализировать DataSet(размер)? Установить свойство в значение ReportCacheMode.Auto? Тогда подскажите, каков алгоритм при таком значении и где можно установить кол-во страниц(в примере выше "при этом в памяти будет храниться только 20-30 страниц (это настраевается)").

3. Может ещё подскажете что-нибудь в поисках решений для генерации больших док-тов? Кстати, есть какие-нибудь данные, о максимальном кол-ве страниц в документе, на которые способен СтимулСофт? Напомню, что в итоге нам нужны PDF -ки. Есть какие-то ограничения?

4. До сих пор не доводилось основательно изучать исходники. Подскажите, плиз. Если я регистрирую DataSet как источник данных. Что происходит потом? Именно этот дадасет и используется для построения отчёта? или он копируется? Или данные перегоняются во внутренние структуры?
К чему я это. Мы собираем данные в XML. С радостью именно в виде XML и отдавали бы их отчётнику. Это сэкономило бы нам время и память. Но, сейчас нам приходится создавать датасет, так-как другого спрособа мы не нашли. Есть какие-то варианты?

Понимаю, что вопросов много, но они(ответы) все для нас действительно важны.

Спасибо.
За продукт, и за ответы ;)
Edward
Сообщения: 930
Зарегистрирован: 09 июн 2006, 12:23

Большие отчёты

Сообщение Edward »

Здравствуйте.
TVV писал(а):1. "есть небольшие ограничения". А можно подробнее? У нас документы(отчёты) генерируются и конвертируются в PDF параллельно в нескольких процессах, и в каждом ещё несколько потоков. Не возникнет ли конфликтов при кэшировании?
Проблем при кэшировании не возникнет. Но в пререлизе от понедельника мы еще немного проработали вопрос с кэшированием при использовании EngineV2.

Небольшие ограничения - к примеру нельзя сохранять в mdc формат в preview, проблема с кросс-линиями. Работа функции PageCount предполагает второй проход после построения отчета. Для этого все страницы повторно извлекаются из кэша.

2. Подскажите наилучшую стратегию. Чаще всего генерится много маленьких документов, но иногда "попадаются" очень большие. Т.е., скорее всего, нужно перед генерацией(рендерингом) устанавливать ReportCacheMode в нужное значение. Как лучше это сделать? Анализировать DataSet(размер)? Установить свойство в значение ReportCacheMode.Auto? Тогда подскажите, каков алгоритм при таком значении и где можно установить кол-во страниц.
Если report.ReportCacheMode = ReportCacheMode.On , то кэширование начнется с первой страницы отчета.
Если report.ReportCacheMode = ReportCacheMode.Auto , то кэширование начнется со страницы, указанной в параметре
Stimulsoft.Report.StiOptions.Engine.ReportCache.LimitForStartUsingCache

Еще есть один параметр - Stimulsoft.Report.StiOptions.Engine.ReportCache.AmountOfQuickAccessPages. Этот параметр опредедляет количество страниц, которые хранятся в основной памяти при переходе от страницы к странице.
3. Может ещё подскажете что-нибудь в поисках решений для генерации больших док-тов? Кстати, есть какие-нибудь данные, о максимальном кол-ве страниц в документе, на которые способен СтимулСофт? Напомню, что в итоге нам нужны PDF -ки. Есть какие-то ограничения?
У нас есть клиенты, у которых в отчетах порядка 40 тысяч страниц. Ограничение возможно только в количестве памяти. Да и размер страниц в памяти для разных отчетов также различается.
4. До сих пор не доводилось основательно изучать исходники. Подскажите, плиз. Если я регистрирую DataSet как источник данных. Что происходит потом? Именно этот дадасет и используется для построения отчёта? или он копируется? Или данные перегоняются во внутренние структуры?
К чему я это. Мы собираем данные в XML. С радостью именно в виде XML и отдавали бы их отчётнику. Это сэкономило бы нам время и память. Но, сейчас нам приходится создавать датасет, так-как другого спрособа мы не нашли. Есть какие-то варианты?
Да, данные, которые Вы передаете в отчет, преобразуются во внутренние DataSet-подобные структуры. В случае с DataSet, данные берутся напрямую из него при условии, что флаг report.CacheAllData = false.

В случае использования XML файлов в качестве источника данных, Вы можете поступить следующим образом:

(report.Dictionary.Databases["MyDataBaseName"] as StiXmlDatabase).PathSchema = Path.Combine(myPath,"MyXMLSchema.xsd");
(report.Dictionary.Databases["MyDataBaseName"] as StiXmlDatabase).PathData = Path.Combine(myPath,"MyXMLSchema.xml");
report.Dictionary.Synchronize();
Спасибо.
За продукт, и за ответы ;)
Мы стараемся :)

Спасибо.
TVV
Сообщения: 27
Зарегистрирован: 08 сен 2006, 15:07

Большие отчёты

Сообщение TVV »

Спасибо!

1. Мы используем 2008.1. Стоит переходить к свежим версиям? Имею ввиду, исключительно из-за вопросов кеширования?
Ну и... не используем в приложении дизайнер. Просто : загружаем, регистрируем данные, рендерим, экспортим.
PageCount используем.
Вот тут, если можно поясните. Если PageCount используем, делаем рендеринг, делаем экспорт.
Кэширование всё ещё актуально? и для подсчёта страниц и для экспорта, страницы будут извлекаться из кэша "порциями"?

2. Ну а вот учитывая, нашу последовательность "рендеринг -> экспорт"(т.е., серверный процесс, без дизайнера, без превью), параметр AmountOfQuickAccessPages на что-то влияет? И если да, то какое оптимальное значение для него?

3. Замечательно! :)

4. Тут есть проблемка. В момент создания(загрузки) отчёта у меня уже есть xml и xsd, в памяти, в строках. Как-то можно выкрутиться, без создания файлов?
Vital
Сообщения: 647
Зарегистрирован: 09 июн 2006, 12:23

Большие отчёты

Сообщение Vital »

Здравствуйте,
1. Мы используем 2008.1. Стоит переходить к свежим версиям? Имею ввиду, исключительно из-за вопросов кеширования?
Нет, не стоит.
Ну и... не используем в приложении дизайнер. Просто : загружаем, регистрируем данные, рендерим, экспортим.
PageCount используем.
Вот тут, если можно поясните. Если PageCount используем, делаем рендеринг, делаем экспорт.
Кэширование всё ещё актуально? и для подсчёта страниц и для экспорта, страницы будут извлекаться из кэша "порциями"?


Да, но это будет происходит медленнее. Дело в том, что количество страниц неизвестно в момент построения. Как неизвестны и итоги по отчету. Поэтому они расставляются после построения отчета путем прохода по необходимым страницам.
2. Ну а вот учитывая, нашу последовательность "рендеринг -> экспорт"(т.е., серверный процесс, без дизайнера, без превью), параметр AmountOfQuickAccessPages на что-то влияет? И если да, то какое оптимальное значение для него?
Это количество страниц, которые одновременно находится в памяти. Оптимальное значение сказать трудно. Чем ближе онон к количеству страниц в отчете тем лучше. Реальное значение между 50 и 100 страницами.
4. Тут есть проблемка. В момент создания(загрузки) отчёта у меня уже есть xml и xsd, в памяти, в строках. Как-то можно выкрутиться, без создания файлов?
Самое простое в Вашем случае загрузить их DataSet и передать его в отчет. Точно также генератор отчетов поступает с xml файлами.

Спасибо.
TVV
Сообщения: 27
Зарегистрирован: 08 сен 2006, 15:07

Большие отчёты

Сообщение TVV »

Здравстуйте

Мы таки нарвались на ошибку, о возможности возникновения которой я спрашивал

System.IO.IOException: The process cannot access the file 'C:\Documents and Settings\Default User\Local Settings\Application Data\StimulsoftReportsCache\66888b5e48ac4c5aaf4f6d4e70f9ae84\028d11c633e843939d0c5ebf9db91386.mch' because it is being used by another process.

at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)

at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy)

at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, String msgPath, Boolean bFromProxy)

at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access)

at Stimulsoft.Report.Components.StiPagesCollection.SavePage(StiPage page)

at Stimulsoft.Report.Components.StiPagesCollection.AddPageToQuickCache(StiPage page, Boolean savePage)

at Stimulsoft.Report.Components.StiPagesCollection.Add(StiPage page)

at Stimulsoft.Report.Render.StiRenderProvider.Render(StiReport report, StiRenderState state)

at Stimulsoft.Report.StiReport.Render(StiRenderState renderState)

at DocumentFormatting.StimulSoftDocConverterPlugin.Converter.GetReport(IDictionary`2 dictReports, Int64 templateId, DateTime onDate, DataSet dsDocument, String waterMark)

at DocumentFormatting.StimulSoftDocConverterPlugin.Converter.ConvertDoc(IDictionary`2 dictReports, ServiceSettings settings, DataSet dsDocument, StimulSoftOutFormat ownOutFormat, Int64 templateId, DateTime onDate, String XML, String path, String waterMark, Int32& pageCount)



2009-03-06 16:23:19,652 [STP SmartThreadPool Thread #1] ERROR Foris.DocumentFormatting.Core.Transformation


System.Reflection.ReflectionTypeLoadException: Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information.

at System.Reflection.Module._GetTypesInternal(StackCrawlMark& stackMark)

at System.Reflection.Assembly.GetTypes()

at Foris.DocumentFormatting.Core.Transformation.TryToLoadConverterPlugin(String path)

------------------------------------
как быть?
Edward
Сообщения: 930
Зарегистрирован: 09 июн 2006, 12:23

Большие отчёты

Сообщение Edward »

Здравствуйте.

Скажите, а как происходит формирование отчетов (или их использование)?

При каждом рендеринге отчета происходит безусловная генерация нового пути на основе случайного guid. Повторения пути быть не должно.

Вы не могли бы предоставить больше информации о проблеме?

Спасибо.
TVV
Сообщения: 27
Зарегистрирован: 08 сен 2006, 15:07

Большие отчёты

Сообщение TVV »

Сорри, за задержку с ответом : у нас тут навалилось...
Например сейчас мне сообщили, что при тестах темповые файлы Стимулсофта "отожрали" больше 100 гиг на диске.
Это ещё нужно проверить, но... может подскажете, как должна происходить очистка темповых файлов?

По поводу формирования отчётов...
коротко... схематически

Есть статический класс Converter. У него есть статический метод ConvertDocBulk. Он в цикле вызывает свой метод ConvertDoc.
Кэширование отчётов происходит на 2-х уровнях.
1. В рамках процесса кэшируем сборки(статическое поле m_Assemblies).
2. В рамках одной "балковой" операции ConvertDocBulk создаётся структура Dictionary dictReports в которой храняться экземпляры отчётов.

приблизительно так выглядит код(половину выкинул, т.к. она не имела отношения к данной проблеме)

---------------------------------------------------
public byte[][] ConvertDocBulk()
{
Dictionary dictReports = new Dictionary();

for (int i = 0; i dictReports...)
{
dsDocument.Clear();
StringReader rdr = new StringReader(XML);
dsDocument.ReadXml(rdr, XmlReadMode.IgnoreSchema);

StiReport report = GetReport(dictReports, key);
MemoryStream stream = new MemoryStream();
report.ExportDocument(ecrOutFormat, stream);
buf = stream.ToArray();

//dsDocument.Dispose();stream.Close(); report.RenderedPages.Clear(); report.Dispose();

return buf;
}


static StiReport GetReport(IDictionary dictReports, string key, DataSet dsDocument)
{
StiReport report;

byte[] template = Template.GetDocTemplateData(key);

if (dictReports.ContainsKey(key))
report = dictReports[key];
else
lock (m_ForAssembliesLock)
{
if (!m_Assemblies.ContainsKey(key))
{
report = new StiReport();

report.Load(template);

MemoryStream strm = new MemoryStream();

report.Compile(strm);

byte[] asmDump = strm.ToArray();

m_Assemblies.Add(key, Assembly.Load(asmDump));

strm.Close();
}

report = StiReport.GetReportFromAssembly(m_Assemblies[key]);

dictReports.Add(templateHashKey, report);
}

SetDataSetName(report, dsDocument);

report.Dictionary.DataStore.Clear();

report.RegData(dsDocument.DataSetName, dsDocument);

report.Render(false);

return report;
}


----------------------
Как-то так...
Edward
Сообщения: 930
Зарегистрирован: 09 июн 2006, 12:23

Большие отчёты

Сообщение Edward »

Здравствуйте.

Спасибо за эту информацию, проверим и будем разбираться с проблемой, если именно так все и обстоит.

Спасибо.
TVV
Сообщения: 27
Зарегистрирован: 08 сен 2006, 15:07

Большие отчёты

Сообщение TVV »

Если есть новости - поделитесь, плиз...
Jan
Сообщения: 495
Зарегистрирован: 19 фев 2009, 11:14

Большие отчёты

Сообщение Jan »

Здравствуйте,

Извините потеряли Ваш топик. По поводу проблемы с файлами на диске. В версии 2008.2 есть один недочет. Удаление файлов происходит в методе Dispose отчета. Но если у отчета есть скомпилированный отчет, то метод Dispose фактически не вызывается. В версии 2009.1 эта проблема уже поправлена. Добавьте такую строку в Ваш код:

Код: Выделить всё

if (rep.CompiledReport != null)
  rep.CompiledReport.Dispose();
По второму вопросу. Ошибку воспроизвести не удалось. Попробуйте пожалуйста последний пререлиз билд (от 23 марта) мы добавили несколько дополнительных проверок в наш код.

Спасибо.
Ответить