четверг, 28 июня 2018 г.

Как работают индексы и их использование в Django


О чем эта статья

Данная статья не будет академическим изложением проблем индексирования в база данных, а будет затрагивать один маленький практический аспект использования индексов для выборки данных. Если отвечать на вопрос заголовка - о деталях и внимательном чтении документации, но я не такой педант (во всяком случае не всегда), мне значительно более интересно экспериментально посмотреть суть проблемы.

Окружение и приложение

Есть Django Web-приложение на python 2.7 (не спрашивайте почему не 3.х). Web-приложение состоит из нескольких типов Worker классов для взаимодействия как с внешними сервисами по HTTP, так и с локальным аналогом данных сервисов, использующих для хранения СУБД MySQL. Мы имеем следующие объекты в модели данных: языковая пара и общая таблица для отображения одного текста в другой:

class LocalTranslationMatrixLanguagesPair(models.Model):
    @classmethod
    def create(cls, language1, language2):
        return cls(language1=language1, language2=language2)

    language1 = models.CharField(u'language1', max_length=4, null=False)
    language2 = models.CharField(u'language2', max_length=4, null=False)

    class Meta:
        unique_together = (u'language1', u'language2')

class LocalTranslationMatrix(models.Model):
    @classmethod
    def create(cls, dictionary, languages, text1, text2, is_main):
        return cls(dictionary=dictionary, languages=languages, text1=text1, text2=text2, is_main=is_main)

    dictionary = models.ForeignKey(Dictionary, related_name=u'local_matrix_dictionary', null=False)
    languages = models.ForeignKey(LocalTranslationMatrixLanguagesPair, related_name=u'local_matrix_language_pair')
    text1 = models.CharField(u'text1', max_length=512, null=False, db_index=True)
    text2 = models.CharField(u'text2', max_length=512, null=False, db_index=True)
    is_main = models.BooleanField(u'is_main')

Самое главное здесь наличие индексов по полям text1 и text2. В MySQL в таблице, на которую отображается LocalTranslationMatrix хранится около 2 млн. строк с перспективой расширения до 10 млн и более.

Использование индексов

Из вышеприведенного кода можно сказать, что у нас есть пары текстов для сопоставления для разных пар языков. Есть задача поиска текста как по столбцу text1, так и по text2 с учетом того, что повторы текста могут быть по этим столбцам, но для разных пар языков. Для решения этой задачи будет использоваться функция filter с использованием функции Q для составления запросов. Так вот вся суть этой статьи заключается в следующем предложении: экспериментально я определил, что наилучшим образом поиск строк происходит в том случае, когда составление запроса происходит по столбцам, с которыми связаны индексы, и чем короче запрос, тем быстрее происходит выборка данных, по сравнению с поиском по индексам и фильтрация по другим столбцам.

Например, такой запрос БЕЗ ИНДЕКСОВ:
translations = LocalTranslationMatrix.objects.filter(Q(text1=translation_request.text) &
                                                                                   Q(languages=lang_pair.id))
на 2 млн строк выполняется за время ~2-3 сек

Если его модифицировать следующим образом и использовать индексы:
translations = LocalTranslationMatrix.objects.filter(Q(text1=translation_request.text))

то он будет выполнен за ~1 мс и меньше

А фильтрация на объектах в памяти питоновского процесса будет выполнена намного быстрее.

Маленькая хитрость или проблемы с длинными индексами

 В mysql при индексах на столбцах длиннее 767 байт (255 символов на utf-8 с 3 байтами на символ) возникают проблемы: не создается база данных или не применяется миграция, для этого я создаю отдельную миграцию, которая выполняет следующее:

 # -*- coding: utf-8 -*-
from __future__ import unicode_literals
import os
from django.db import migrations, models



class Migration(migrations.Migration):

    #initial = False

    dependencies = [
        ('translator', '0001_initial')
    ]
   
    operations = [
        migrations.RunSQL("SET GLOBAL innodb_large_prefix = ON; SET GLOBAL innodb_file_format=Barracuda;"),
        migrations.RunSQL("ALTER TABLE translator_translation ROW_FORMAT=DYNAMIC;"),
        migrations.RunSQL("ALTER TABLE translator_localtranslationmatrix ROW_FORMAT=DYNAMIC;")

]

Иногда возникают проблемы с созданием индексов через модель, их также можно создать через RunSQL:

 migrations.RunSQL("CREATE INDEX translator_translation_i_original_text ON translator_translation(original_text)"),

Заключение

Практика показывает, что самый лучший вариант - поиск ИСКЛЮЧИТЕЛЬНО только по индексам, а фильтрацию лучше проводить на объектах в памяти.


понедельник, 2 апреля 2018 г.

Восстановление БД с изменением имени в MSSQL

Проблема
Необходимо скопировать и восстановить одну из БД на том же инстансе (экземпляре) SQL сервер.

У MSSQL  все базы данных имеют логическое имя и обычно состоят из 2 файлов (файла данных и файла лога), имеющие следующие имена:

logicalName_Data.mdf
и
logicalName_Log.ldf

Иногда возникают ситуации когда необходимо "скопировать" БД на этот же инстанс SQL-сервера, но с новым логическим именем т.к., например, копируемая БД используется одним или несколькими приложениями.

Решение
Я не нашел как решить эту проблему в SQL Management Studio без операций по переименовыванию исходной БД (одно из условий: БД используется одним из приложений, поэтому ее трогать нельзя). Решение довольно простое, но для этого еужно написать TSQL-инструкцию.

1. Вывод списка файлов бэкапа:
RESTORE FILELISTSTONLY FROM DISK = 'E:\backups\mydb.bak'

в моем случае я получил mydb] для Data-файла и mydb]_log для файла логов

2. теперь скопируем имена файлов из выведенной таблицы в слебующую инструкцию:

RESTORE DATABASE myNewDb FROM DISK = 'E:\backups\mydb.bak'
WITH
RECOVERY,
MOVE 'mydb]' TO 'E:\db\data\myNewDb.mdf',
MOVE 'mydb]_log' TO 'E:\db\logs\myNewDb.ldf'; 

База восстановлена с новым именем myNewDb.

вторник, 2 января 2018 г.

Развертывание Asp Net Core на IIS

Как развертывается Asp Net Core

Asp Net Core - это как Проктор энд Гэмбл т.е. два в одном флаконе: фрэймворк и Web-сервер, а само веб приложение  имеет вид консольного приложения, развертываемого через IWebHost с предварительной настройкой сервисов, миддлваре и т.п. Все относительно просто в случаях, когда разработка идет на машине с установленной Visual Studio. Для запуска веб приложений в Asp Net Core используется веб-сервер Kestrel. И, казалось, бы нет никаких сложностей для запуска веб-приложения на IIS. Но, столкнувшись с такой задачей я набил кучу шишек, о чем и хочу рассказать в этом посте.

Создание Net Core пула и подключение модуля AspNetCore

Как известно в IIS имеются пулы, которые, используются во-первых, для изоляции одних приложений от других, а, во-вторых, для простоты настройки однотипных приложений. И если запустить настройку пула приложения на IIS, то можно увидеть, что Net Core в нем напрочь отсутствует (предварительно я установил Net Core Sdk), всего 3 варианта таргет фрэймворка для пула: 2.0, 4.0 и неуправляемый код. Для Asp Net Core нужно выбрать последний. 

Но и это еще не все: выше я писал, что Asp Net Core веб-приложение развертывается на веб-сервере Kestrel, а как же тогда подключить IIS, дело в том, что IIS подключается как прокси: все запросы, пришедшие на HTTP порт приложения, развернутого на IIS, маршрутизируются через модуль AspNetCore в Kestrel, обрабатываются приложением, а ответ направляется в IIS. За это взаимодействие отвечает AspNetCore модуль, который необходимо установить в IIS отдельно от Net Core Sdk!!!! (https://docs.microsoft.com/ru-ru/aspnet/core/fundamentals/servers/aspnet-core-module). После инсталляции в списке модулей должна быть эта строка (предварительно (сначала) необходимо установить VS2015 C++ Redistributable Package):
Кроме всего этого в Web.config необходимо указать использование этого модуля и путь к целевой сборке (приложению), например, мое приложение - E3App.Web.dll и Web.Config имеет следующий вид:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.webServer>
    <handlers>
      <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" />
    </handlers>
    <aspNetCore
        processPath="dotnet"
        arguments=".\E3App.Web.dll"
        stdoutLogEnabled="true"
        stdoutLogFile=".\logs\stdout" />
  </system.webServer>
</configuration>

Этот файл, как и многое другое, генерируется в процессе публикации проекта (Publish), однако, я не думал, что он играет роль, т.к. он в явном виде отсутствует в проекте. Но он очень важный! Особенно атрибут stdoutLogEnabled, по умолчанию этот атрибут имеет значение false, что для разработчика означает следующее: любое исключение произошедшее при запуске приложение будет "проглочено", а в качестве результата мы увидим на странице что-то вроде: "Оопс, а что-то сломалось". Включаем и идем дальше.

Старая добрая БД и EF Core

Следующим приколом на пути к запуску приложения стала сама БД: я поставил Sql Server 2012, предполагая, что EF нет дела до версии SQL сервера, но не тут-то было (хотя мне казалось, что ву меня был рабочий проект под 12 версию сервера). Текст исключения в стандартном выводе мне ничего не говорил о том, почему у меня ломается приложение при старте. Однако, подозрительным было то, что при отладке приложение стартовало без каких-либо проблем, а на IIS - ломалось. Тогда я решил заменить 12 SQL Server на SQL Server 2016 и вуаля, текст ошибки стал другим. Теперь приложение жаловалось на то, что нет прав на создании новой БД при подключении к таблице master (тут все тривиально, нужна роль sysadmin для пользователя под которым выполняется подключение). Хотелось бы сделать ремарку о том, что EF работает с БД по парадигме Code First (сам создает скрипт для создания БД, всех таблиц и связей между ними). Тут тоже пришлось помучиться, т.к. можно сделать строку подключения с полным указаниям логина и пароля (в appsettings.json):

  "ConnectionStrings": {
    "Storage": "Server=DEV-HOST\\SQLEXPRESS;Database=e3app;
    User ID=developer;Password=123;MultipleActiveResultSets=true"
  }


 Но это не всегда удобно использовать заранее созданную учетную запись, иногда необходимо использовать Windows-аутентификацию, казалось бы просто выдал права (роль sysadmin) своей Windows учетной записи:

"ConnectionStrings": {
    "Storage": "Server=DEV-HOST\\SQLEXPRESS;Database=e3app;
    Integrated Security=SSPI;MultipleActiveResultSets=true"
 }


 но нет в БД, оказывается, EF лезет через другую учетку. Экспериментальным способом включая данную роль у логинов по очереди, определил, что это  учетная запись BULTIN\Users (а если посмотреть, кто создал БД - IIS APPPOOL/AspNetCore).



Заключение

Казалось бы тривиальная задача, но она отняла у меня кучу времени, я убил, наверное, пару дней чистого времени пытаясь понять, что происходит и почему все работает не так, как нужно. Надеюсь, что этот пост поможет тем, кто столкнулся с такой же проблемой: деплоя на IIS Asp Net Core веб приложения.



воскресенье, 12 ноября 2017 г.

Анонимный доступ в Samba

Как настроить полностью анонимный доступ к Samba сервису

Данное очень короткое сообщение, скорее напоминание самому себе как это делается,  т.к. на одном из моих одноплатников, а именно на том, на котором крутился мой файлообменник, умерла карта памяти, чтобы не вспоминать по 10 раз снова как это делается (а внутри домашней сети мне нет смысла делать доступ по паролю) я здесь выложу файл конфигурации Samba для полностью анонимного доступа:

[global]
workgroup = FAMILY
server string = Cubie Samba Server
dos charset = cp1251
unix charset = utf8
dns proxy = no
security = user
browseable = yes
log file = /media/other/samba/smbd.log
syslog = 0
map to guest = Bad Password
guest account = nobody
browseable = yes

[shared]
comment = Guest access share
path = /media/samba/shared
browseable = yes
read only = no
guest ok = yes
writable = yes
public = yes
available = yes

Комментировать тут особенно нечего, поэтому если кому-то понадобится, пользуйтесь на здоровье.

четверг, 9 ноября 2017 г.

Десериализация в ASP NET Core 2.0

Будни кросс-платформенного Web от Microsoft

ASP NET Core базируется на платформе NET Core, которая, в свою очередь является кросс-платформенной, на данный момент доступна версия 2.0.х (у меня NET Core работает, что под Windows 7, что под Linux Mint 18).  Сам ASP NET Core включает в себя Entity Framework, Json Converter (от Newtonsoft), IoC и т.п. Сегодня пойдет речь о работе с Json, точнее о том, что я в итоге получил.

Приколы с POST и PUT и десериализацией из Json

Предположим у нас есть два проекта в солюшене, пусть они называются ClickPlatform.Dto и ClickPlatform.Mvc. В первом у нас объявлены классы Dto - объектов, а вот втором - Web API с набором контроллеров с методами (Get, Post, Put и Delete для обработки одноименных HTTP-методов и действий).

У нас есть следующий класс Dto:

    public class Listing
    {
          public Listing() { }

          public Listing(Guid id, string name, AdShortInfo[] linkedAd = null, string status = null,                                              TotalStatistics stats = null)
          {
               Id = id;
               Name = name;
               LinkedAd = linkedAd;
               Status = status;
               Stats = stats;
          }

          public Guid Id { get; set; }
          public string Name { get; set; }
          public AdShortInfo[] LinkedAd { get; set; }
          public string Status { get; set; }
          public TotalStatistics Stats { get; set; }
    }

Понятно, что для получения объекта и коллекции объектов используем Get-методы, с сериализацией тут все ок, все хорошо работает. и мы получаем либо коллекцию объектов, либо отдельный объект по id. Чудеса начинаются при использовании методов Post и Put внутри следующего контроллера

    [Produces("application/json")]
    [Route("api/[controller]")]
    public class ListingController : Controller
    {
        .// ...
       
        [HttpPost]
        public void Post([FromBody] Dto.Internal.Listing listing)
        {
    _listingManager.Create(listing);
        }

        [HttpPut("{id}")]
        public void Put([FromRoute]Guid id, [FromBody]Dto.Internal.Listing listing)
        {
            _listingManager.Update(id, listing);
        }
       
        // ...
   }

   Пробуем дернуть Post при этом устанавливаем content-type=application/json и charset=utf-8. и передаем следующий json: {"id":"","status":"active","name":"Evil_One","linkedAd":[], "stats":""}


Точка останова показывает нам, что наш объект - null.


Если мы поставим object, то получим следующее:

[HttpPost]
public void Post([FromBody] /*Dto.Internal.Listing*/ object listing)
{
     //_listingManager.Create(listing);
}


Теперь объект в теле определился, получается, что Json не может десериализовать объект в Dto.Internal.Listing. Почему же так происходит?  Все дело оказывается в том, что если для value type значение в Json не задано, то считается, что там null, а null нельзя использовать для value-типов, поэтому приходится везде ставить Nullable<T>. В вышеприведенном коде поменяет  свойство Guid Id {get; set;} на Guid? Id {get; set;}. И теперь смело можем передавать запрос со значением ""  в качестве Guid

При этом сам Newtonsoft.Json не соизволил проинформировать о том, что он не может десериализовать тип. Что ж вот такая она десериализация объектов в Asp NET.

Послесловие (послевкусие)
Попробовал я ASP NET Core и не могу сказать, что это супер платформа, не могу сказать, что это именно то, что нужно для разработки. В ней вроде как бы все есть, но что-то в ней не так. Многие вещи кажутся странными: как например молчаливая обработка ошибок, подтягивание Nuget пакетов для самых очевидных вещей вроде System.Data и многое другое. Если сюда добавить работу только на VS17 (на мой взгляд, худшая студия начиная с 2003, даже 2010 была лучше).





понедельник, 4 сентября 2017 г.

Как начать работать с HDL и ПЛИС (FPGA)

Предисловие

Планирую написать ряд статей, про внутреннее устройство ПЛИС и их программирование. В данном сообщении я планирую дать направление читателю, что нужно прочитать для того, чтобы начать разрабатывать для ПЛИС.

Современные тенденции

К сожалению, а может быть и к счастью (в зависимости как на это посмотреть) разработка современной электроники, особенно цифровой, но не только сводится к описанию цифровых функций и автоматов сводится к описанию их на основе одного из HDL (Hardware Description Language) -языков описания аппаратуры. На данный момент, существуют следующие языки описания аппаратуры: AHDL, VHDL, Verilog и System Verilog. Сами ПЛИС (CPLD, FPGA) представляют собой квадратные матрицы ячеек (состоящих из сотен - тысяч, в зависимости  от ресурсов ПЛИС, логических элементов), к этим ячейкам подходят магистрали источников синхросигналов (клоков) и линий питания (+5 или +3,3 В) и земли.  К слову говоря, современные ПЛИС (7 серия от Xilinx, 5 поколение Cyclone и т.п.) - это SoC в которых кроме, самой ПЛИС присутствует процессорное ядро и аппаратная поддержка различных интерфейсов таких, как : USB, Ethernet, CAN, SPI, I2C, RS232 и др.

Три кита разработки цифровых устройств с использованием ПЛИС (FPGA)

 1. Основа всего это алгебра логики (булева алгебра) и способы построения простых цифровых схем и автоматов с использованием алгебры логики.

2. Схемотехника входных и выходных каскадов логических элементов (для понимания, что такое высокоимпедансное Z-состояние, нагрузочные характеристики элементов, схемы с открытым коллектором).

3. И, конечно, 3 этап это способы построения простых цифровых схем с использованием языков описания аппаратуры.

Алгебра логики

Основными в алгебре логики являются следующие вещи:

1) Принцип двойственности
2) Теорема Де-Моргана 
 
 Эти два принципа можно посмотреть, например, здесь: https://studme.org/2002061028280/tovarovedenie/algebra_logiki . Позже сам напишу про алгебру логики.

Так же следует упомянуть про способы представления (алгебраическое, табличное и в виде карт/диаграм Карно и Вена) и минимизации логических функций через карты Карно или другие методы, например, метод Мак-Класки (https://ru.wikipedia.org/wiki/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%9A%D1%83%D0%B0%D0%B9%D0%BD%D0%B0_%E2%80%94_%D0%9C%D0%B0%D0%BA-%D0%9A%D0%BB%D0%B0%D1%81%D0%BA%D0%B8).

Одна неплохая презентация про алгебру логики: https://drive.google.com/file/d/0B9GLCHSwsJn8cURyT3BOUEVxdVE/view?usp=sharing

После понимания математических основ цифровой электроники нужно двигаться к способам реализации простых цифровых схем клмбинационной логики (логики не зависящей от состояния схемы):

- мультиплексоры
- дешифраторы
- преобразователи кода
- и другие схемы.

Вот, например, https://drive.google.com/open?id=0B9GLCHSwsJn8NmxtTVNUOVZZbWs

 Следующий шаг - изучение последовательностных схем (схемы зависящие от состояния и сигналов на входе схемы).  Такими схемами являются:

-триггеры
-счетчики
-регистры
-генераторы
и др.

Например, https://distant.msu.ru/pluginfile.php/38192/mod_resource/content/1/%D0%9B%D0%B5%D0%BA%D1%86%D0%B8%D1%8F%204.pdf

или

https://drive.google.com/open?id=0B9GLCHSwsJn8YkJZeGtVZzZ4LTQ

а также ознакомиться с описанием цифровых автоматов (которых, 2 основных вида: Мили и Мура (https://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%B2%D1%82%D0%BE%D0%BC%D0%B0%D1%82%D1%8B_%D0%9C%D1%83%D1%80%D0%B0_%D0%B8_%D0%9C%D0%B8%D0%BB%D0%B8)

Схемотехника логических элементов

Данный раздел в большей степени относится к разаботке цифровых устройств с использованием дискретных микросхем, однако, в ряде моментов при проектировании с использованием ПЛИС эти знания также оказываются необходимыми

Прежде всего схемотехника зависит от типа логики: ТТЛ (ТТЛШ), КМОП и ЭСЛ: http://www.inp.nsk.su/students/radio/lectures/Pulse/07.pdf

Параметры логических элементов:
 http://myrepititor.ru/electronics/82-Osnovnye_xarakteristiki_i_parametry_logicheskix_eleme.html

http://audioakustika.ru/node/1555

Языки HDL, способы проектирования
У меня довольно большаыя подборка книг по ПЛИС: https://drive.google.com/open?id=0B9GLCHSwsJn8Z0Y3U24ybmxjVjA

Если использовать Verilog, то стоить начать с Verilog и VerilogTutorial, если VHDL - то "Языки Verilog и VHDL", кроме того среди этого архива есть документ с "Золотыми ссылками по HDL".


Что будет в продолжении?

В будущем планирую пройтись по каждому из этих пунктов и написать цикл статей с примерами дизайна цифровых схем (на github).

суббота, 29 июля 2017 г.

C++ symbol lookup error при запуске приложения

Суть проблемы
 
Недавно, занимаясь одним из своих С++ проектов обнаружил следующее занимательное поведение программы, использующих динамическую библиотеку. На самом деле, неважно какая библиотека вызвала данную проблему, я уверен, что это не имеет никакого значения. Но в моем случае данная проблема возникла с библиотекой libuhd. Я собрал для себя специальную версию ibuhd, успешно скомпилировал и слинковал приложение с либой и бац! при запуске:
linux; GNU C++ version 4.8.5; Boost_105800; UHD_003.010.001.001-0-unknown

/home/michael/Projects/eclipse/C++/wirelessdriver/UhdRadio/Debug/UhdRadio: symbol lookup error: /home/michael/Projects/eclipse/C++/wirelessdriver/UhdRadio/Debug/UhdRadio: undefined symbol: _ZN20radio_ctrl_core_30004makeEbN5boost10shared_ptrIN3uhd9transport12zero_copy_ifEEES5_jRKSs




Причина в отсутствии функции в классе библиотеки или самого класса! Собирал я это чудо cmake, и, как оказалось, в cmake также можно задавать видимость определенных классов, но предварительно я снял все ограничения, экспортировал все, что есть. Сижу недоумеваю, пью кофе и тихо матерюсь ("С++, что же ты со мной делаешь!").

Дьявол скрывается в мельчайших деталях

В первую очередь решил проверить, а есть ли в библиотеке такой символ. Для таких целей в Linux есть утилита nm. Она позволяет вывести список экспортируемых символов, но он оказывается гигантским, поэтому используем ее совместно с grep, получаем:

~/Projects/eclipse/C++/wirelessdriver/UhdRadio/uhd-release_003_010_001_001/host/build/lib> nm -D libuhd.so | grep _ZN20radio_ctrl_core_30004makeEbN5boost10shared_ptrIN3uhd9transport12zero_copy_ifEEES5_jRKSs
00000000004e1ff0 T _ZN20radio_ctrl_core_30004makeEbN5boost10shared_ptrIN3uhd9transport12zero_copy_ifEEES5_jRKSs


Да, что же такое! Нужные символы есть, возможно не все зависимости (библиотеки) есть в системе, но ldd показывает, что все ОК (показывает откуда (путь) подлинковываются либы). И тут меня осенило!!! Я собирал целую массу версий uhd и параллельно ставил ее из пакетов, а что же говорит ldd относительно этой либы в моей утилите???  А говорит он, что либа при запуске приложения берется не из того, же источника откуда проводилась линковка! Понятно, что для запуска либа должна быть в LD_LIBRARY_PATH, но оба пути находятся в этой переменной, а при запуске либа тянется из первого в порядке упоминания пути, а моих изменений там вовсе НЕТ. Правим и наслаждаемся спокойной работой дальше.

Заключение

С++ , GCC люблю я вас! Настолько много в вас неожиданных сюрпризов...

Распространение Windows-приложений (Chocolatey)

Менеджеры пакетов для ОС Windows В большинстве дистрибутивов Linux есть свои менеджеры пакетов: в Ubuntu/Mint это apt и deb, в OpenSuse э...