Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 (MSSQL + XmlTextReader) вешает файлы  [new]
RubinDm
Member

Откуда:
Сообщений: 461
Есть тривиальная CLR-функция,
create function [dbo].[ReadXml]
	( @path nvarchar(max)
	) returns xml
as external NAME [MyAssembly].[MyType].[MyMethod]
go


Реализация MyMethod предельно простая:
[return: SqlFacet(MaxSize = -1)]
[SqlFunction(Name = "MyMethod", DataAccess = DataAccessKind.None, SystemDataAccess = SystemDataAccessKind.None)]
static public SqlXml MyMethod([SqlFacet(MaxSize = -1)] SqlString path)
{
	if (path.IsNull)
		return SqlXml.Null;
	var stream = File.Open(path.Value, FileMode.Open, FileAccess.Read, FileShare.Read);
	var reader= XmlTextReader(stream);
	if (reader== null)
		return SqlXml.Null;
	return new SqlXml(reader);
}


Работает шустро, и не дорого.
Но есть нюанс: эта скалярка активно используется для чтения xml-файлов, в цикле, по списку известных путей. Головняк начинается после чтения файлов, уже ЗА пределами MSSQL. Если файлов прочитано было много, то последние файлы остаются "подвешенными", т.о. удалить их не представляется возможным. Этот эффект имеет плавающий характер, количество подвешенных файлов меняется между запусками цикла. В связи с этим вопрос: с чего бы это сиквел держит файлы открытыми? как убедить его, что неплохо было бы диспозить ридер и стрим под ним??? На данный момент отпустить стрим удается только в результате отключения службы сиквела, но сами понимаете, сервак при этом мгновенно остывает, и пользователи съедят меня, и религия не позволяет... Я мог бы читать стрим ридером самостоятельно, диспозить все явным образом и затем возвращать строку с xml-содержимым, но это странное решение, которое поубивает профит от XmlReader'а. + это не мой код, и формально это верный код, трогать который не хотелось бы. Что посоветуете?
ps:
Microsoft SQL Server 2014 - 12.0.2269.0 (X64) 
	Jun 10 2015 03:35:45 
	Copyright (c) Microsoft Corporation
	Express Edition (64-bit) on Windows NT 6.3 <X64> (Build 10586: )
22 янв 16, 02:38    [18714041]     Ответить | Цитировать Сообщить модератору
 Re: (MSSQL + XmlTextReader) вешает файлы  [new]
aleks2
Guest
Неча на зеркало пенять, коли рожа крива.

Почему MS SQL должен за вас закрывать ридер и стрим?
Я понимаю, с "fully managed code" каждая кухарка мнит себя программистом.
Но от судьбы не уйдешь.

1. Прочитать xml в переменную.
2. Закрыть и уничтожить явно ридер и стрим.
22 янв 16, 05:51    [18714070]     Ответить | Цитировать Сообщить модератору
 Re: (MSSQL + XmlTextReader) вешает файлы  [new]
Сон Веры Павловны
Member

Откуда:
Сообщений: 6201
RubinDm,

возьмите себе за непреложное правило: всё, что реализует IDisposable, заворачивать в using statement - тогда не будет таких "непонятных" ситуаций. В данном случае и FileStream, и XmlTextReader реализуют IDisposable, поэтому код должен выглядеть так:
[return: SqlFacet(MaxSize = -1)]
[SqlFunction(Name = "MyMethod", DataAccess = DataAccessKind.None, SystemDataAccess = SystemDataAccessKind.None)]
static public SqlXml MyMethod([SqlFacet(MaxSize = -1)] SqlString path)
{
	if (path.IsNull)
		return SqlXml.Null;
	SqlXml result = null;
	using(var stream = File.Open(path.Value, FileMode.Open, FileAccess.Read, FileShare.Read))
	using(var reader= XmlTextReader(stream))
	{
		if (reader== null)
			return SqlXml.Null;
		result = new SqlXml(reader);
	}
	return result;
}
22 янв 16, 06:06    [18714074]     Ответить | Цитировать Сообщить модератору
 Re: (MSSQL + XmlTextReader) вешает файлы  [new]
Glory
Member

Откуда:
Сообщений: 104751
RubinDm
Работает шустро, и не дорого.

Быстрее и дешевле BULK-а ?
22 янв 16, 10:14    [18714457]     Ответить | Цитировать Сообщить модератору
 Re: (MSSQL + XmlTextReader) вешает файлы  [new]
RubinDm
Member

Откуда:
Сообщений: 461
Glory
RubinDm
Работает шустро, и не дорого.

Быстрее и дешевле BULK-а ?
Glory, я перепроверю (на выходных) и, само собой, поделюсь результатами.
22 янв 16, 12:29    [18715112]     Ответить | Цитировать Сообщить модератору
 Re: (MSSQL + XmlTextReader) вешает файлы  [new]
RubinDm
Member

Откуда:
Сообщений: 461
Сон Веры Павловны
RubinDm,
возьмите себе за непреложное правило: всё, что реализует IDisposable, заворачивать в using statement - тогда не будет таких "непонятных" ситуаций. В данном случае и FileStream, и XmlTextReader реализуют IDisposable, поэтому код должен выглядеть так: ...
Вообще ситуация "непонятой" не являлась с самого начала, все достаточно очевидно. За пример кода - спасибо, но я одинаково хорошо владею IDispose'ом как правой рукой так и левой, о чем недвусмысленно намекнул на старте темы. Что касается непреложного правила.. как Вы прокомментируете наличие конструктора System.Data.SqlTypes.SqlXml, который принимает на вход Stream|XmlReader? На кой нужны такие конструкторы, если правило, озвученное Вами является непреложным?
22 янв 16, 12:48    [18715240]     Ответить | Цитировать Сообщить модератору
 Re: (MSSQL + XmlTextReader) вешает файлы  [new]
RubinDm
Member

Откуда:
Сообщений: 461
aleks2,ignored
22 янв 16, 12:49    [18715245]     Ответить | Цитировать Сообщить модератору
 Re: (MSSQL + XmlTextReader) вешает файлы  [new]
Сон Веры Павловны
Member

Откуда:
Сообщений: 6201
RubinDm
как Вы прокомментируете наличие конструктора System.Data.SqlTypes.SqlXml, который принимает на вход Stream|XmlReader? На кой нужны такие конструкторы, если правило, озвученное Вами является непреложным?

И чего же здесь непонятного? SqlXml принимает на вход XmlReader, в конструкторе считывает из него данные, и на этом - всё. Закрыть этот ридер - ваша обязанность.
22 янв 16, 13:17    [18715435]     Ответить | Цитировать Сообщить модератору
 Re: (MSSQL + XmlTextReader) вешает файлы  [new]
RubinDm
Member

Откуда:
Сообщений: 461
Сон Веры Павловны
RubinDm
как Вы прокомментируете наличие конструктора System.Data.SqlTypes.SqlXml, который принимает на вход Stream|XmlReader? На кой нужны такие конструкторы, если правило, озвученное Вами является непреложным?
SqlXml принимает на вход XmlReader, в конструкторе считывает из него данные, и на этом - всё. Закрыть этот ридер - ваша обязанность.

Сон Веры Павловны
Закрыть этот ридер - ваша обязанность.
Формально Вы правы. Но! MSSQL в части CLR принципиально запилен таким образом, что нет никакой возможности передать в SQL через CLR что-либо, на что остались бы какие-то ссылки за пределами SQL. Например, мы не можем передать в возвращаемый SqlXml в качестве параметра экземпляр XmlReader, ссылка на который хранилась бы еще и в какой-то статической переменной CLR-сборки. Причины таких ограничений очевидны, и это заведомо обоснованные ограничения. Т.о. можно утверждать, что в конечном итоге на выходе из CLR-метода ссылка на XmlReader останется только у SQL'я, и SQL это знает. Внимание, вопрос: почему бы SQL'ю не озаботиться диспозом переданных ему ссылок самостоятельно? Это было бы логично, если учесть, что никто кроме самого SQL'я к этим ссылкам доступа не имеет, и диспозить их не может.
+ отдельная тема: не понятно, зачем SqlXml прям сразу засасывает в себя все содержимое XmlReader'а целиком? Строго говоря, не факт, что прочитанное содержимое будет востребовано в полном объеме. Если переменная типа XML будет использована для поиска одной ноды по заданным условиям (что вполне вероятно), то в реализации SqlXml разумно было бы использовать XPathNavigator, который работает что называется "за еду". Но разработчики SQL видимо не сильно заморачивались эвристикой на тему "как будут юзать XML", и потому засосали все за раз (так проще, и надежнее, хоть и дороже). Чтож.. это тоже неплохой вариант. Но в таком случае непонятно, зачем были реализованы конструкторы, принимающие IDisposable, в какой-то степени правоцирующие написание неверного кода (кто-то ведь написал ту CLR-ку).
22 янв 16, 13:57    [18715791]     Ответить | Цитировать Сообщить модератору
 Re: (MSSQL + XmlTextReader) вешает файлы  [new]
Glory
Member

Откуда:
Сообщений: 104751
RubinDm
Внимание, вопрос: почему бы SQL'ю не озаботиться диспозом переданных ему ссылок самостоятельно? Это было бы логично, если учесть, что никто кроме самого SQL'я к этим ссылкам доступа не имеет, и диспозить их не может.

Для сбора просьб и предложений по MSSQL у производителя есть специальный ресурс

RubinDm
+ отдельная тема: не понятно, зачем SqlXml прям сразу засасывает в себя все содержимое XmlReader'а целиком? Строго говоря, не факт, что прочитанное содержимое будет востребовано в полном объеме. Если переменная типа XML будет использована для поиска одной ноды по заданным условиям (что вполне вероятно), то в реализации SqlXml разумно было бы использовать XPathNavigator, который работает что называется "за еду". Но разработчики SQL видимо не сильно заморачивались эвристикой на тему "как будут юзать XML", и потому засосали все за раз (так проще, и надежнее, хоть и дороже). Чтож.. это тоже неплохой вариант. Но в таком случае непонятно, зачем были реализованы конструкторы, принимающие IDisposable, в какой-то степени правоцирующие написание неверного кода (кто-то ведь написал ту CLR-ку).

Это тема для программирования на .Net
22 янв 16, 14:04    [18715843]     Ответить | Цитировать Сообщить модератору
 Re: (MSSQL + XmlTextReader) вешает файлы  [new]
Сон Веры Павловны
Member

Откуда:
Сообщений: 6201
RubinDm
Например, мы не можем передать в возвращаемый SqlXml в качестве параметра экземпляр XmlReader, ссылка на который хранилась бы еще и в какой-то статической переменной CLR-сборки. Причины таких ограничений очевидны, и это заведомо обоснованные ограничения. Т.о. можно утверждать, что в конечном итоге на выходе из CLR-метода ссылка на XmlReader останется только у SQL'я, и SQL это знает. Внимание, вопрос: почему бы SQL'ю не озаботиться диспозом переданных ему ссылок самостоятельно?

Посмотрите исходники SqlXml: http://referencesource.microsoft.com/#System.Data/System/Data/SQLTypes/SqlXml.cs,72fdadba7711986e
Именно в случае перегрузки конструктора, принимающего XmlReader, ссылка на этот ридер не хранится нигде внутри экземпляра SqlXml - из ридера просто вычитываются все нужные данные, и всё. Это во-первых. Во-вторых, вызов Dispose не есть уничтожение ссылки на объект - вы вполне его можете сдлать, даже если кто-то еще удерживает ссылку на экземпляр IDisposable. Поэтому в данном случае можно смело диспозить экземпляр XmlTextReader прямо в вашей функции. Если что - я всегда именно так и поступаю в случае SqlXml, и это ни разу не давало никаких побочных эффектов.
22 янв 16, 15:01    [18716309]     Ответить | Цитировать Сообщить модератору
 Re: (MSSQL + XmlTextReader) вешает файлы  [new]
Сон Веры Павловны
Member

Откуда:
Сообщений: 6201
RubinDm
не понятно, зачем SqlXml прям сразу засасывает в себя все содержимое XmlReader'а целиком? Строго говоря, не факт, что прочитанное содержимое будет востребовано в полном объеме. Если переменная типа XML будет использована для поиска одной ноды по заданным условиям (что вполне вероятно), то в реализации SqlXml разумно было бы использовать XPathNavigator, который работает что называется "за еду"

И что дальше? Ленивое подтягивание данных прямо во время выполнения запроса/ХП? Я сомневаюсь, что такое вообще возможно.
22 янв 16, 15:10    [18716399]     Ответить | Цитировать Сообщить модератору
 Re: (MSSQL + XmlTextReader) вешает файлы  [new]
RubinDm
Member

Откуда:
Сообщений: 461
Сон Веры Павловны
RubinDm
не понятно, зачем SqlXml прям сразу засасывает в себя все содержимое XmlReader'а целиком? Строго говоря, не факт, что прочитанное содержимое будет востребовано в полном объеме. Если переменная типа XML будет использована для поиска одной ноды по заданным условиям (что вполне вероятно), то в реализации SqlXml разумно было бы использовать XPathNavigator, который работает что называется "за еду"
И что дальше? Ленивое подтягивание данных прямо во время выполнения запроса/ХП? Я сомневаюсь, что такое вообще возможно.
Именно ленивое. Это вполне возможно, и даже полезно в части расхода ram в случае, если содержимое не будет востребовано в полном объеме, например через XPathNavigator. Про исходники - да, сам уже заглянул. В конечном счете все сводится, помимо прочего, например к необходимости быть готовым ответить за запрос значения SqlXml.Value более одного раза. В исходниках видно, что в случае использования ридера по факту создается копия содержимого, хранение которой организовано в виде MemoryStream. Если вместо ридера мы сразу даем стрим, и если он CanSeek, то сиквел видимо считает, что и такой стрим ему сгодится. Правда он его оборачивает wrapper'ом, цель которого явным образом задокументирована в исходниках: when xmlreader calls close, do not close the orginial stream. И получается, что оригинальный стрим закроется только с подачи GC. Я в принципе не против.. ) пусть так.. но при таком раскладе, возможно, стоило бы на SqlXml натянуть реализацию IDisposable. Не так уж дорого это стоило бы, и ресурсы освобождались бы куда более вменяемо и предсказуемо.

Вобщем, академический интерес удовлетворен, считаю тему закрытой.
22 янв 16, 16:04    [18716838]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить