Идея исправления и улучшения ID Factory

Теги:
 

awarm

разработчик l2j-сервера

NetImperia:
Как используются идентификаторы пользователей. Это что что-бы получить пользователя, идет обращение к ID в базе. А затем по этому ID ищится ник и работа по никам производится?
Если так то это вообще берд полный. Как я понимаю в идеале нужно получать ID, login, ID клана, Имя клана и ник персонажа тогда когда игрок входит на сервер. И всегда его помнить пока он не выйдет.
Тогда не нужно будет думать что использовать для доступа. Можно использовать как ник так и ID. Если конечно его нужно тут использовать. А не читать из базы его каждый раз.
 
Внутри игры используются уникальные идентификаторы, присваиваемые каждому объекту. Внутри сервера эти идентификаторы соотносятся соответственно с типом объекта и его параметрами. Так что действительно хранить эти ID в базе совсем не обязательно. Более сервер никак к идентификаторам не привязан. т.е. если тебе нужен аккаунт, делаешь выборку по login + hash(pass), при этом получаешь внутрибазовый id пользователя, по которому дольше идет поиск связанных записей.
NetImperia:
Как не крути, а по ID доступ в разы быстрее если по этому полю построен индекс. Так как тогда все это число помещается в индексе если конечно оно в разумных переделах.А если делать поиск по строкам. То тогда это медленее будет. Потому что тогда в индексе не будет отиндексировано все слово ,а только часть его. И поиск будет медлеенее.
Balancer:
(напомню, имена у нас уникальные, скорость поиска по индексированной строке в mysql не ниже, чем поиск по индексированным числовым значениям).
 

Заблуждаешся. Медленее. На маленьких базах этого не будет заметно. Но когда записей много тогда это очень заметно.
 
Насколько я знаю, индексы строятся на основе хешей значений. Соответственно при поиске из значения получается его хеш и дальше идет уже поиск по числу. Но как только у нас строковая переменная оказывается неиндексированной, вот тут-то и идет зверское падение скорости (на больших таблицах)
NetImperia:
Balancer:
- Идентифиакторы раздаются с минимального значения при каждом старте сервера каждому новому создаваемому объекту и в БД не хранятся
 

А как тогда обращаться к мобам или каким-то вещам в квестах?
Например какой-нить квест пойди найди то-то. И дотронься. Это так для примера.
 

ID объекта ВНУТРИ игры будет создаваться при создании игрового объекта, и будет являться указателем на объект. Ты ведь не спрашиваешь каждый раз, по каким именно адресам в памяти располагается та ли иная программа, а просто используешь указатель на нее.

NetImperia:
Balancer:
- не потребуется сжатие БД
 

В этом я сомневаюсь. Все равно придется. Например после удаления пользователя.
 
Имелось ввиду переназначение ID. Это тоже надо будет делать, но во много раз реже, чем сейчас.
NetImperia:
Balancer:
- проще будет работать визуально с БД (скажем, сразу видишь, какому игроку принадлежит предмет)
 

Пользователи и админы вообще не должны лазать в базу что-бы произвести какие-то манипуляции. Все эти манипуляции должны делаться через интерфейсы в игре либо WEB интерфейсы.
 
Полностью согласен.

На самом деле такая структура БД есть наследие от баз данных хранящихся в текстовых файлах. И делать все это надо было еще в момент перехода на SQL. В крайнем случае, при смене формата хранения вещей. Так что это уже давно назрело.
 
RU NetImperia #17.08.2005 13:42
+
-
edit
 

NetImperia

новичок
awarm:
Внутри игры используются уникальные идентификаторы, присваиваемые каждому объекту. Внутри сервера эти идентификаторы соотносятся соответственно с типом объекта и его параметрами. Так что действительно хранить эти ID в базе совсем не обязательно. Более сервер никак к идентификаторам не привязан. т.е. если тебе нужен аккаунт, делаешь выборку по login + hash(pass), при этом получаешь внутрибазовый id пользователя, по которому дольше идет поиск связанных записей.
 


Я правильно понимаю? Те ID что у нас в базе и те что используются в самой игре разные?
Если да то в игре используются числовые ID или строки? Как игровые ID выглядят?


awarm:
Насколько я знаю, индексы строятся на основе хешей значений. Соответственно при поиске из значения получается его хеш и дальше идет уже поиск по числу. Но как только у нас строковая переменная оказывается неиндексированной, вот тут-то и идет зверское падение скорости (на больших таблицах)
 


Да правильно. Но тут есть нюанс. Если это строка то хэш делается не по всей строке. А только по ее части.
Тяжела жизнь программиста: радость находки своего бага всегда омрачает осознание собственной тупости...  

awarm

разработчик l2j-сервера

Да. ты понял правильно. id внутри сервера не обязательно должны соответствовать внутрибазовым. главное, что-бы они были уникальные в период одного запуска сервера. игровые ID являются 4байтовым целым беззнаковым числом (по моему).
А насчет хеша - честно говоря насколько я знаю, это зависит от реализации. на MS SQL насколько я знаю делается по все строке.
 
+
-
edit
 

Balancer

администратор
★★★★★
zabbix:
ок, а если сделать пул свободных идентификаторов?
 


Так было в самом первом варианте ID Factory. Как только сервер становился более-менее популярным, сбор стартовых данных о пуле занимал до получаса :) Плюс такая система жрёт очень много памяти - каждую дырку в адресах помнить нужно.

>Ну если внутриигровые генерить по порядку, а в базе использовать нормальные свои, тогда можно

Да, я так и предлагаю

>что то вроде геодаты планируется ?

Геодата на основе сбора перемещений игроков, которую я задумывал ещё в начале года, мне очень не нравится. Ну да её и без меня уже почти доделали :) Геодату нужно делать на основе клиентских данных. Но это нужен упёртый товарищ, который разберёт формат :)

>Дайте мне готовую пхп страницу для отображения колличества игроков он-лине и топа

Я же писал - поищи на форуме. Я пару раз давал код.

>А свои это какие? держать bigint-овые поля с autoencrement-ом? сдается мне что это не вариант...

Чем не вариант? Даже обычного INT'а хватит на несколько лет, а в случае чего, переиндексация займёт считанные секунды и без сбоев в общей БД. Считать просто в новую таблицу и всё :)

>Ты считаешь, что текстовые поля будут лучше???

С точки зрения скорости выборки в mysql - пофиг. И все принадлежности, типа id игроков или кланов безусловно лучше делать текстовыми, именными. Очень упростится ручная работа с БД :)

>вопрос какой способ генерации IDшников выбрать для базы

Тут велосипед изобретать не нужно. Автоинкремент и всё :)

>Как используются идентификаторы пользователей. Это что что-бы получить пользователя, идет обращение к ID в базе. А затем по этому ID ищится ник и работа по никам производится?

Работа по никам не ведётся вообще. Ники используются только для отображения и, редко, для всяких админских фич, типа //target {имя}. Каждый игрок в памяти сервера хранится своим игровым идентификатором. Все операции с ним делаются по идентификатору.

>Как не крути, а по ID доступ в разы быстрее если по этому полю построен индекс.

По ID доступ быстрее в разЫ если НЕ построен индекс :) Индекс создаёт хеш как для числовых, так и для строковых данных. Так что время выборки практически не различается (на строках есть мелкие штрафы, типа конфликтов хешей и т.п., но это капля в море).

>Заблуждаешся. Медленее. На маленьких базах этого не будет заметно. Но когда записей много тогда это очень заметно.

Объём базы в 600 тыс. записей - достаточен для тестов? :D Это у меня на основном форуме. Разница, повторюсь, не наблюдается. А на l2j-сервере, дай Бог, 1/10 этого количества записей. Впрочем, даже если бы выборка строковых данных была бы на пару порядков тормознее, роли бы это не сыграло, т.к. лишние полсекунды ожидания при логине погоды не сделали бы. Так же разница будет измеряться тысячными долями :)

>А как тогда обращаться к мобам или каким-то вещам в квестах?

Мобы в таблицах не имеют ID. Им назначается уникальный ID каждый раз при старте сервера, при генерации спавна.

>Бардак с ID потому что надо делать ID Auto Increment. Тогда будет все ок.

Проблема в том, что при таком подходе ID кончатся очень быстро (32 бита со знАком), а переиндексация их занимает дофига времени. Особенно, если долго её не делаешь. Кроме того, при переиндексации, например, теряется возможность отслеживать судьбу той или иной вещи (в нынешнем варианте это невозможно, в варианте с фиксированными ID можно будет вести такие логи, для решения множественных игровых споров такого рода).

>В этом я сомневаюсь. Все равно придется. Например после удаления пользователя.

Это не сжатие идентификаторов :)

>Пользователи и админы вообще не должны лазать в базу что-бы произвести какие-то манипуляции. Все эти манипуляции должны делаться через интерфейсы в игре либо WEB интерфейсы.

Прекрасно, но ты такой интерфейс сделаешь? Тогда вопрос отпадёт. Пока же все задачи приходится решать через phpMyAdmin или из консоли :)

>Те ID что у нас в базе и те что используются в самой игре разные?

В текущей реализации - нет. И из-за этого и возник этот топик :)

>А насчет хеша - честно говоря насколько я знаю, это зависит от реализации. на MS SQL насколько я знаю делается по все строке

В MySQL можно явно указывать по скольки символам строки строить хеш. По умолчанию - строится на всю строку.
… чтобы понять рекурсию, нужно сперва понять рекурсию …  

Serge
Serge2

новичок
Balancer:
>Ну если внутриигровые генерить по порядку, а в базе использовать нормальные свои, тогда можно

Да, я так и предлагаю
 
Ну вот и славненько! Над новой схемой базы уже начал работать? если да, то положи в root/L2J Balancer/sql... глянуть хоцца.
Balancer:
>А свои это какие? держать bigint-овые поля с autoencrement-ом? сдается мне что
это не вариант...

Чем не вариант? Даже обычного INT'а хватит на несколько лет, а в случае чего, переиндексация займёт считанные секунды и без сбоев в общей БД. Считать просто в новую таблицу и всё :)
 
Ну... тебе виднее ;-) а переиндексация будет "insert into items_tmp (...) select ... from items" ? если да (типа не надо будет делать изменения в других таблицах изза смены ID-шника) то это ваше рулить будет. можно по дефоулту при старте сервера включить - по времени займет пару секунд...
Balancer:
>Ты считаешь, что текстовые поля будут лучше???

С точки зрения скорости выборки в mysql - пофиг. И все принадлежности, типа
id игроков или кланов безусловно лучше делать текстовыми, именными. Очень
упростится ручная работа с БД :)
 
Выборка - да, быстро. а вот инсерт мульти-индексного поля может начать тормозить (в одном проекте есть рабочая табличка где есть 6 текстовых полей, одно с уникальным индексом, остальные просто проиндексированы,один биг инт автоинкремент примари кей, 4 дате, 1 датетайм ну и несколько тиниинтов - дык на 434856 записях инсерт туда делается почти пол секунды) хотя если будет всего один текстовый индекс может все будет пучком...
...I'm very responsible person, then something goes wrong I'm response.  
RU NetImperia #17.08.2005 21:54
+
-
edit
 

NetImperia

новичок
[quote|Balancer:]
zabbix:
>Пользователи и админы вообще не должны лазать в базу что-бы произвести какие-то манипуляции. Все эти манипуляции должны делаться через интерфейсы в игре либо WEB интерфейсы.

Прекрасно, но ты такой интерфейс сделаешь? Тогда вопрос отпадёт. Пока же все задачи приходится решать через phpMyAdmin или из консоли :)
 


Дык я уже начал делать. Только мне так никто и не сказал что в первую очередь надо редактировать? Желательно по пунктам. Что-бы я так и шол по пунктам...
Тяжела жизнь программиста: радость находки своего бага всегда омрачает осознание собственной тупости...  

awarm

разработчик l2j-сервера

Balancer:
>Пользователи и админы вообще не должны лазать в базу что-бы произвести какие-то манипуляции. Все эти манипуляции должны делаться через интерфейсы в игре либо WEB интерфейсы.

Прекрасно, но ты такой интерфейс сделаешь? Тогда вопрос отпадёт. Пока же все задачи приходится решать через phpMyAdmin или из консоли
 

Если бы речь шла о реализации с использованием MSSQL и .NET, я бы все это наваял за несколько дней, но ... увы, увы, увы...
Собственно у меня сейчас для этих целей используется набор запросов в Navicat. Но от полностью ручной генерации кода я уже отвык... да и не люблю РНР. Потому и нет пока такой панели. А к ASP.NET MySQL подключить не получилось несмотря на наличие соответствующего коннектора.

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

zabbix

разработчик OpenWorlds
вот посидел неделю назад немного, а потом дела более срочные появились

code text
  1. package net.sf.l2j.controller;
  2.  
  3. import java.io.DataInputStream;
  4. import java.io.IOException;
  5. import java.io.PrintStream;
  6. import java.net.ServerSocket;
  7. import java.net.Socket;
  8. import java.util.logging.Logger;
  9.  
  10. import net.sf.l2j.gameserver.Shutdown;
  11.  
  12. public class InteractiveSocket extends Thread
  13. {
  14.        
  15.         static Logger           _log = Logger.getLogger(InteractiveSocket.class.getName());
  16.  
  17.         public static void main(String[] args) throws IOException
  18.         {
  19.         }
  20.        
  21.     public void close()
  22.     {
  23.         _log.info("closing interactive controller");
  24.         this.interrupt();
  25.         try
  26.         {
  27.             server.close();
  28.         }
  29.         catch (IOException e)
  30.         {
  31.         }
  32.     }
  33.  
  34.        
  35.         public void run()
  36.         {
  37.                
  38.                 while(true)
  39.                 {
  40.                         _log.info("waiting for connections...");
  41.                         try
  42.                         {
  43.                                 client = server.accept();
  44.                                 is = new DataInputStream(client.getInputStream());
  45.                                 os = new PrintStream(client.getOutputStream());
  46.                                 _log.info("New connection from " + client.getInetAddress().getHostAddress());
  47.  
  48.                                 while(true)
  49.                                 {
  50.                                         String cmd = is.readLine();
  51.                                         _log.info("I've got command: <"+cmd+">");
  52.                                        
  53.                                         if(cmd.equals("quit"))
  54.                                         {
  55.                                                 client.close();
  56.                                         }
  57.                                         else if(cmd.equals("announce"))
  58.                                         {
  59.                                                 //blah
  60.                                         }
  61.                                         else if(cmd.equals("restart"))
  62.                                         {
  63.                                                 shutdown = new Shutdown(30, true);
  64.                                                 shutdown.start();
  65.                                         }
  66.                                 }
  67.                         }
  68.                         catch (IOException e)
  69.                         {
  70.                                 System.out.println(e.getMessage());
  71.                         }
  72.                 }
  73.  
  74.         }
  75.        
  76.         public InteractiveSocket(String threadName)
  77.         {
  78.                 System.out.println("cons #1");
  79.         }
  80.        
  81.         public InteractiveSocket() throws IOException
  82.         {
  83.                
  84.                 super("InteractiveSocket");
  85.                
  86.                 System.out.println("cons #2");
  87.  
  88.                 try
  89.                 {
  90.                         server = new ServerSocket(2009);
  91.                 }
  92.                 catch (IOException e)
  93.                 {
  94.                         System.out.println(e.getMessage());
  95.                 }
  96.                
  97.                 System.out.println("Interactive socket ready on port 2009");
  98.         }
  99.        
  100.         private ServerSocket    server;
  101.         private Socket                  client;
  102.         private DataInputStream is;
  103.     private PrintStream         os;
  104.     private static Shutdown shutdown = null;
  105. }


ногами не бейте - яву плохо знаю :rolleyes:
Речи тайна Йоды магистра раскрыта - на Форте программист просто старый оказывается он.  
+
-
edit
 

zabbix

разработчик OpenWorlds
а, ну я тыкал это в net.sf.l2j.Server

вот так:
public static InteractiveSocket ctrlsock;
....
ctrlsock = new InteractiveSocket();
ctrlsock.start();
Речи тайна Йоды магистра раскрыта - на Форте программист просто старый оказывается он.  
+
-
edit
 

Balancer

администратор
★★★★★
>Ну вот и славненько! Над новой схемой базы уже начал работать?

Нет ещё. Боюсь, что гарантированно этим только через одни выходные смогу заняться. Там работы довольно много, кучу классов придётся переписывать. Выкладывать, естественно, в L2J Balancer буду сперва :)

>а переиндексация будет "insert into items_tmp (...) select ... from items" ? если да (типа не надо будет делать изменения в других таблицах изза смены ID-шника) то это ваше рулить будет. можно по дефоулту при старте сервера включить - по времени займет пару секунд...

Именно так.

>Выборка - да, быстро. а вот инсерт мульти-индексного поля может начать тормозить (в одном проекте есть рабочая табличка где есть 6 текстовых полей, одно с уникальным индексом, остальные просто проиндексированы,один биг инт автоинкремент примари кей, 4 дате, 1 датетайм ну и несколько тиниинтов - дык на 434856 записях инсерт туда делается почти пол секунды) хотя если будет всего один текстовый индекс может все будет пучком...

Думаю, что вставка в нашем случае будет тоже нересурсоёмкой. Впрочем, даже в противном случае - всё равно записей будет на порядок меньше, чем в твоём примере. У меня на сервере сейчас около 50 тыс. итемов в БД. Так что пять сотых секунды при твоём тайминге - это хорошо. Вставки бывают редко. Но мне кажется, что должно быть ещё быстрее. М.б. на днях замеры проведу.

> Только мне так никто и не сказал что в первую очередь надо редактировать?

Как я уже говорил - лично мне phpMyAdmin + консольный SQL пока по уши хватает :) Если ещё и индексы "именные" будут, то всё ещё больше упростится (на пару десятков символов в каждый запрос меньше вбивать - одним LEFT JOIN меньше :) )

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

Ага. Спасибо, что напомнил. Постараюсь время выкроить. Просто я насобачился по ssh рестартовать. Прошу кого-нибудь анонс в игру сделать, а потом - "pkill java" :)
… чтобы понять рекурсию, нужно сперва понять рекурсию …  
AD Реклама Google — средство выживания форумов :)
+
-
edit
 

zabbix

разработчик OpenWorlds
up

code text
  1. [SYSTEM]: 0,[SafeIDFactory::WHDeposit] -> realCount: 1
  2. [SYSTEM]: 0,[SafeIDFactory::WHDeposit] -> ooid: 268556091 noid: 268556491
  3. [SYSTEM]: 0,[SafeIDFactory::WHDeposit] -> realCount: 1
  4. [SYSTEM]: 0,[SafeIDFactory::WHDeposit] -> ooid: 268556093 noid: 268556494
  5. [SYSTEM]: 0,[SafeIDFactory::WHDeposit] -> realCount: 1
  6. [SYSTEM]: 0,[SafeIDFactory::WHDeposit] -> ooid: 268685458 noid: 268556495
  7. [SYSTEM]: 0,[SafeIDFactory::WHDeposit] -> realCount: 1
  8. [SYSTEM]: 0,[SafeIDFactory::WHDeposit] -> ooid: 268685457 noid: 268556496
  9. [SYSTEM]: 0,[SafeIDFactory::WHDeposit] -> realCount: 1
  10. [SYSTEM]: 0,[SafeIDFactory::WHDeposit] -> ooid: 268685459 noid: 268556497
  11. [SYSTEM]: 0,[SafeIDFactory::WHDeposit] -> realCount: 1
  12. [SYSTEM]: 0,[SafeIDFactory::WHDeposit] -> ooid: 268704148 noid: 268556498
  13. [SYSTEM]: 0,[SafeIDFactory::WHDeposit] -> realCount: 1
  14. [SYSTEM]: 0,[SafeIDFactory::WHDeposit] -> ooid: 268599565 noid: 268556502
  15. [SYSTEM]: 0,[SafeIDFactory::WHDeposit] -> realCount: 1
  16. [SYSTEM]: 0,[SafeIDFactory::WHDeposit] -> ooid: 268579541 noid: 268556505
  17. [SYSTEM]: 0,[SafeIDFactory::WHDeposit] -> realCount: 1
  18. [SYSTEM]: 0,[SafeIDFactory::WHDeposit] -> ooid: 268579458 noid: 268556506
  19. [SYSTEM]: 0,[SafeIDFactory::WHDeposit] -> realCount: 1
  20. [SYSTEM]: 0,[SafeIDFactory::WHDeposit] -> ooid: 268579310 noid: 268556507
  21. [SYSTEM]: 0,[SafeIDFactory::WHDeposit] -> realCount: 1
  22. [SYSTEM]: 0,[SafeIDFactory::Drop]: ooid:268684076 noid: 268684076
  23. [SYSTEM]: 0,[SafeIDFactory::Drop]: oid collision!? noid: 268684076
  24. [SYSTEM]: 0,[SafeIDFactory::Drop]: ooid:268545043 noid: 268545043
  25. [SYSTEM]: 0,[SafeIDFactory::Drop]: oid collision!? noid: 268545043
  26. [SYSTEM]: 0,[SafeIDFactory::Drop]: ooid:268537631 noid: 268537631
  27. [SYSTEM]: 0,[SafeIDFactory::Drop]: oid collision!? noid: 268537631
  28. [SYSTEM]: 0,[SafeIDFactory::Drop]: ooid:268624896 noid: 268624896
  29. [SYSTEM]: 0,[SafeIDFactory::Drop]: oid collision!? noid: 268624896
  30. [SYSTEM]: 0,[SafeIDFactory::Drop]: ooid:268624896 noid: 268624896
  31. [SYSTEM]: 0,[SafeIDFactory::Drop]: oid collision!? noid: 268624896
  32. [SYSTEM]: 0,[SafeIDFactory::Drop]: ooid:268715066 noid: 268715066
  33. [SYSTEM]: 0,[SafeIDFactory::Drop]: oid collision!? noid: 268715066
  34. [SYSTEM]: 0,[SafeIDFactory::Drop]: ooid:268554083 noid: 268554083
  35. [SYSTEM]: 0,[SafeIDFactory::Drop]: oid collision!? noid: 268554083
  36. [SYSTEM]: 0,[SafeIDFactory::Drop]: ooid:268557409 noid: 268557409
  37. [SYSTEM]: 0,[SafeIDFactory::Drop]: oid collision!? noid: 268557409
  38. [SYSTEM]: 0,[SafeIDFactory::Drop]: ooid:268559168 noid: 268559168
  39. [SYSTEM]: 0,[SafeIDFactory::Drop]: oid collision!? noid: 268559168


вот тут как должно быть в идеале - после дропа ид должен быть не изменным, но при текущем механизме работы йдфактори такого следует избегать; зато когда в варехаус кладешь ид новый выделяется :D
а вот как бывает еще:

code text
  1. [SYSTEM]: 0,[SafeIDFactory::Drop]: ooid:268564374 noid: 268560075
  2. [SYSTEM]: 0,[SafeIDFactory::Drop]: ooid:268556009 noid: 268560248
  3. [SYSTEM]: 0,[SafeIDFactory::Drop]: ooid:268556009 noid: 268560285


тут уже коллизий нету, что херня полная, ибо ид новый, но лучше дружит с идфактори, хотя потенциально создает траблы с concurrent dbupdate
Речи тайна Йоды магистра раскрыта - на Форте программист просто старый оказывается он.  

в начало страницы | новое
 
Поиск
Настройки
Твиттер сайта
Статистика
Рейтинг@Mail.ru