Большие отчёты
Большие отчёты
Добрый день.
Столкнулись с проблемой нехватки памяти при генерации(и конвертации в PDF) нескольких больших(болле 500 страниц) отчётов.
Поискал подобные вопросы и нашел вот что :
"есть возможность кэшировать отчеты. В этом случае только небольшая часть отчета находится в памяти, все остальное выгружается в спецаильный кэш. Скорость построения падает не сильно, есть небольшие ограничения, но потребеление памяти радикально меньше. Т.е. можно построить очень большие отчеты, при этом в памяти будет храниться только 20-30 страниц (это настраевается) отчета. Включить кэширование можно при помощи свойства ReportCacheMode отчета."
Ну, вот у меня и возник ряд вопросов.
1. "есть небольшие ограничения". А можно подробнее? У нас документы(отчёты) генерируются и конвертируются в PDF параллельно в нескольких процессах, и в каждом ещё несколько потоков. Не возникнет ли конфликтов при кэшировании?
2. Подскажите наилучшую стратегию. Чаще всего генерится много маленьких документов, но иногда "попадаются" очень большие. Т.е., скорее всего, нужно перед генерацией(рендерингом) устанавливать ReportCacheMode в нужное значение. Как лучше это сделать? Анализировать DataSet(размер)? Установить свойство в значение ReportCacheMode.Auto? Тогда подскажите, каков алгоритм при таком значении и где можно установить кол-во страниц(в примере выше "при этом в памяти будет храниться только 20-30 страниц (это настраевается)").
3. Может ещё подскажете что-нибудь в поисках решений для генерации больших док-тов? Кстати, есть какие-нибудь данные, о максимальном кол-ве страниц в документе, на которые способен СтимулСофт? Напомню, что в итоге нам нужны PDF -ки. Есть какие-то ограничения?
4. До сих пор не доводилось основательно изучать исходники. Подскажите, плиз. Если я регистрирую DataSet как источник данных. Что происходит потом? Именно этот дадасет и используется для построения отчёта? или он копируется? Или данные перегоняются во внутренние структуры?
К чему я это. Мы собираем данные в XML. С радостью именно в виде XML и отдавали бы их отчётнику. Это сэкономило бы нам время и память. Но, сейчас нам приходится создавать датасет, так-как другого спрособа мы не нашли. Есть какие-то варианты?
Понимаю, что вопросов много, но они(ответы) все для нас действительно важны.
Спасибо.
За продукт, и за ответы
Столкнулись с проблемой нехватки памяти при генерации(и конвертации в PDF) нескольких больших(болле 500 страниц) отчётов.
Поискал подобные вопросы и нашел вот что :
"есть возможность кэшировать отчеты. В этом случае только небольшая часть отчета находится в памяти, все остальное выгружается в спецаильный кэш. Скорость построения падает не сильно, есть небольшие ограничения, но потребеление памяти радикально меньше. Т.е. можно построить очень большие отчеты, при этом в памяти будет храниться только 20-30 страниц (это настраевается) отчета. Включить кэширование можно при помощи свойства ReportCacheMode отчета."
Ну, вот у меня и возник ряд вопросов.
1. "есть небольшие ограничения". А можно подробнее? У нас документы(отчёты) генерируются и конвертируются в PDF параллельно в нескольких процессах, и в каждом ещё несколько потоков. Не возникнет ли конфликтов при кэшировании?
2. Подскажите наилучшую стратегию. Чаще всего генерится много маленьких документов, но иногда "попадаются" очень большие. Т.е., скорее всего, нужно перед генерацией(рендерингом) устанавливать ReportCacheMode в нужное значение. Как лучше это сделать? Анализировать DataSet(размер)? Установить свойство в значение ReportCacheMode.Auto? Тогда подскажите, каков алгоритм при таком значении и где можно установить кол-во страниц(в примере выше "при этом в памяти будет храниться только 20-30 страниц (это настраевается)").
3. Может ещё подскажете что-нибудь в поисках решений для генерации больших док-тов? Кстати, есть какие-нибудь данные, о максимальном кол-ве страниц в документе, на которые способен СтимулСофт? Напомню, что в итоге нам нужны PDF -ки. Есть какие-то ограничения?
4. До сих пор не доводилось основательно изучать исходники. Подскажите, плиз. Если я регистрирую DataSet как источник данных. Что происходит потом? Именно этот дадасет и используется для построения отчёта? или он копируется? Или данные перегоняются во внутренние структуры?
К чему я это. Мы собираем данные в XML. С радостью именно в виде XML и отдавали бы их отчётнику. Это сэкономило бы нам время и память. Но, сейчас нам приходится создавать датасет, так-как другого спрособа мы не нашли. Есть какие-то варианты?
Понимаю, что вопросов много, но они(ответы) все для нас действительно важны.
Спасибо.
За продукт, и за ответы
Большие отчёты
Здравствуйте.
Небольшие ограничения - к примеру нельзя сохранять в mdc формат в preview, проблема с кросс-линиями. Работа функции PageCount предполагает второй проход после построения отчета. Для этого все страницы повторно извлекаются из кэша.
Если report.ReportCacheMode = ReportCacheMode.Auto , то кэширование начнется со страницы, указанной в параметре
Stimulsoft.Report.StiOptions.Engine.ReportCache.LimitForStartUsingCache
Еще есть один параметр - Stimulsoft.Report.StiOptions.Engine.ReportCache.AmountOfQuickAccessPages. Этот параметр опредедляет количество страниц, которые хранятся в основной памяти при переходе от страницы к странице.
В случае использования 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();
Спасибо.
Проблем при кэшировании не возникнет. Но в пререлизе от понедельника мы еще немного проработали вопрос с кэшированием при использовании EngineV2.TVV писал(а):1. "есть небольшие ограничения". А можно подробнее? У нас документы(отчёты) генерируются и конвертируются в PDF параллельно в нескольких процессах, и в каждом ещё несколько потоков. Не возникнет ли конфликтов при кэшировании?
Небольшие ограничения - к примеру нельзя сохранять в mdc формат в preview, проблема с кросс-линиями. Работа функции PageCount предполагает второй проход после построения отчета. Для этого все страницы повторно извлекаются из кэша.
Если report.ReportCacheMode = ReportCacheMode.On , то кэширование начнется с первой страницы отчета.2. Подскажите наилучшую стратегию. Чаще всего генерится много маленьких документов, но иногда "попадаются" очень большие. Т.е., скорее всего, нужно перед генерацией(рендерингом) устанавливать ReportCacheMode в нужное значение. Как лучше это сделать? Анализировать DataSet(размер)? Установить свойство в значение ReportCacheMode.Auto? Тогда подскажите, каков алгоритм при таком значении и где можно установить кол-во страниц.
Если report.ReportCacheMode = ReportCacheMode.Auto , то кэширование начнется со страницы, указанной в параметре
Stimulsoft.Report.StiOptions.Engine.ReportCache.LimitForStartUsingCache
Еще есть один параметр - Stimulsoft.Report.StiOptions.Engine.ReportCache.AmountOfQuickAccessPages. Этот параметр опредедляет количество страниц, которые хранятся в основной памяти при переходе от страницы к странице.
У нас есть клиенты, у которых в отчетах порядка 40 тысяч страниц. Ограничение возможно только в количестве памяти. Да и размер страниц в памяти для разных отчетов также различается.3. Может ещё подскажете что-нибудь в поисках решений для генерации больших док-тов? Кстати, есть какие-нибудь данные, о максимальном кол-ве страниц в документе, на которые способен СтимулСофт? Напомню, что в итоге нам нужны PDF -ки. Есть какие-то ограничения?
Да, данные, которые Вы передаете в отчет, преобразуются во внутренние DataSet-подобные структуры. В случае с DataSet, данные берутся напрямую из него при условии, что флаг report.CacheAllData = false.4. До сих пор не доводилось основательно изучать исходники. Подскажите, плиз. Если я регистрирую DataSet как источник данных. Что происходит потом? Именно этот дадасет и используется для построения отчёта? или он копируется? Или данные перегоняются во внутренние структуры?
К чему я это. Мы собираем данные в XML. С радостью именно в виде XML и отдавали бы их отчётнику. Это сэкономило бы нам время и память. Но, сейчас нам приходится создавать датасет, так-как другого спрособа мы не нашли. Есть какие-то варианты?
В случае использования 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();
Мы стараемсяСпасибо.
За продукт, и за ответы
Спасибо.
Большие отчёты
Спасибо!
1. Мы используем 2008.1. Стоит переходить к свежим версиям? Имею ввиду, исключительно из-за вопросов кеширования?
Ну и... не используем в приложении дизайнер. Просто : загружаем, регистрируем данные, рендерим, экспортим.
PageCount используем.
Вот тут, если можно поясните. Если PageCount используем, делаем рендеринг, делаем экспорт.
Кэширование всё ещё актуально? и для подсчёта страниц и для экспорта, страницы будут извлекаться из кэша "порциями"?
2. Ну а вот учитывая, нашу последовательность "рендеринг -> экспорт"(т.е., серверный процесс, без дизайнера, без превью), параметр AmountOfQuickAccessPages на что-то влияет? И если да, то какое оптимальное значение для него?
3. Замечательно!
4. Тут есть проблемка. В момент создания(загрузки) отчёта у меня уже есть xml и xsd, в памяти, в строках. Как-то можно выкрутиться, без создания файлов?
1. Мы используем 2008.1. Стоит переходить к свежим версиям? Имею ввиду, исключительно из-за вопросов кеширования?
Ну и... не используем в приложении дизайнер. Просто : загружаем, регистрируем данные, рендерим, экспортим.
PageCount используем.
Вот тут, если можно поясните. Если PageCount используем, делаем рендеринг, делаем экспорт.
Кэширование всё ещё актуально? и для подсчёта страниц и для экспорта, страницы будут извлекаться из кэша "порциями"?
2. Ну а вот учитывая, нашу последовательность "рендеринг -> экспорт"(т.е., серверный процесс, без дизайнера, без превью), параметр AmountOfQuickAccessPages на что-то влияет? И если да, то какое оптимальное значение для него?
3. Замечательно!
4. Тут есть проблемка. В момент создания(загрузки) отчёта у меня уже есть xml и xsd, в памяти, в строках. Как-то можно выкрутиться, без создания файлов?
Большие отчёты
Здравствуйте,
Да, но это будет происходит медленнее. Дело в том, что количество страниц неизвестно в момент построения. Как неизвестны и итоги по отчету. Поэтому они расставляются после построения отчета путем прохода по необходимым страницам.
Спасибо.
Нет, не стоит.1. Мы используем 2008.1. Стоит переходить к свежим версиям? Имею ввиду, исключительно из-за вопросов кеширования?
Ну и... не используем в приложении дизайнер. Просто : загружаем, регистрируем данные, рендерим, экспортим.
PageCount используем.
Вот тут, если можно поясните. Если PageCount используем, делаем рендеринг, делаем экспорт.
Кэширование всё ещё актуально? и для подсчёта страниц и для экспорта, страницы будут извлекаться из кэша "порциями"?
Да, но это будет происходит медленнее. Дело в том, что количество страниц неизвестно в момент построения. Как неизвестны и итоги по отчету. Поэтому они расставляются после построения отчета путем прохода по необходимым страницам.
Это количество страниц, которые одновременно находится в памяти. Оптимальное значение сказать трудно. Чем ближе онон к количеству страниц в отчете тем лучше. Реальное значение между 50 и 100 страницами.2. Ну а вот учитывая, нашу последовательность "рендеринг -> экспорт"(т.е., серверный процесс, без дизайнера, без превью), параметр AmountOfQuickAccessPages на что-то влияет? И если да, то какое оптимальное значение для него?
Самое простое в Вашем случае загрузить их DataSet и передать его в отчет. Точно также генератор отчетов поступает с xml файлами.4. Тут есть проблемка. В момент создания(загрузки) отчёта у меня уже есть xml и xsd, в памяти, в строках. Как-то можно выкрутиться, без создания файлов?
Спасибо.
Большие отчёты
Здравстуйте
Мы таки нарвались на ошибку, о возможности возникновения которой я спрашивал
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)
------------------------------------
как быть?
Мы таки нарвались на ошибку, о возможности возникновения которой я спрашивал
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)
------------------------------------
как быть?
Большие отчёты
Здравствуйте.
Скажите, а как происходит формирование отчетов (или их использование)?
При каждом рендеринге отчета происходит безусловная генерация нового пути на основе случайного guid. Повторения пути быть не должно.
Вы не могли бы предоставить больше информации о проблеме?
Спасибо.
Скажите, а как происходит формирование отчетов (или их использование)?
При каждом рендеринге отчета происходит безусловная генерация нового пути на основе случайного guid. Повторения пути быть не должно.
Вы не могли бы предоставить больше информации о проблеме?
Спасибо.
Большие отчёты
Сорри, за задержку с ответом : у нас тут навалилось...
Например сейчас мне сообщили, что при тестах темповые файлы Стимулсофта "отожрали" больше 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;
}
----------------------
Как-то так...
Например сейчас мне сообщили, что при тестах темповые файлы Стимулсофта "отожрали" больше 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;
}
----------------------
Как-то так...
Большие отчёты
Здравствуйте.
Спасибо за эту информацию, проверим и будем разбираться с проблемой, если именно так все и обстоит.
Спасибо.
Спасибо за эту информацию, проверим и будем разбираться с проблемой, если именно так все и обстоит.
Спасибо.
Большие отчёты
Если есть новости - поделитесь, плиз...
Большие отчёты
Здравствуйте,
Извините потеряли Ваш топик. По поводу проблемы с файлами на диске. В версии 2008.2 есть один недочет. Удаление файлов происходит в методе Dispose отчета. Но если у отчета есть скомпилированный отчет, то метод Dispose фактически не вызывается. В версии 2009.1 эта проблема уже поправлена. Добавьте такую строку в Ваш код:
По второму вопросу. Ошибку воспроизвести не удалось. Попробуйте пожалуйста последний пререлиз билд (от 23 марта) мы добавили несколько дополнительных проверок в наш код.
Спасибо.
Извините потеряли Ваш топик. По поводу проблемы с файлами на диске. В версии 2008.2 есть один недочет. Удаление файлов происходит в методе Dispose отчета. Но если у отчета есть скомпилированный отчет, то метод Dispose фактически не вызывается. В версии 2009.1 эта проблема уже поправлена. Добавьте такую строку в Ваш код:
Код: Выделить всё
if (rep.CompiledReport != null)
rep.CompiledReport.Dispose();
Спасибо.