Scid  4.7.0
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
codec_proxy.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2016-2018 Fulvio Benini
3 
4  * This file is part of Scid (Shane's Chess Information Database).
5  *
6  * Scid is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation.
9  *
10  * Scid is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with Scid. If not, see <http://www.gnu.org/licenses/>.
17  *
18  */
19 
20 /** @file
21  * Implements the CodecProxy class, which serves as base class for non-native
22  * databases.
23  */
24 
25 #ifndef CODEC_PROXY_H
26 #define CODEC_PROXY_H
27 
28 #include "codec.h"
29 #include "codec_memory.h"
30 #include "common.h"
31 #include "game.h"
32 
33 #ifndef MULTITHREADING_OFF
34 #include <atomic>
35 #include <thread>
36 #endif
37 
38 /**
39  * Base class for non-native databases.
40  * Every class derived from ICodecDatabase must keep an @e Index object and the
41  * corresponding @e NameBase object fully updated in memory.
42  * This implies that the virtual function dyn_open() must load in memory the
43  * header's data of all the games; however a dependency between the codecs and
44  * the @e Index class is not desirable.
45  * This class provides an interface that encapsulates the codecs, requiring only
46  * the ability to exchange @e Game objects.
47  */
48 template <typename Derived> class CodecProxy : public CodecMemory {
49  Derived* getDerived() { return static_cast<Derived*>(this); }
50 
51 public:
52  /**
53  * Opens/creates a database encoded in a non-native format.
54  * @param filename: full path of the database to be opened.
55  * @param fMode: valid file access mode.
56  * @returns OK in case of success, an @p errorT code otherwise.
57  */
58  errorT open(const char* filename, fileModeT fMode);
59 
60  /**
61  * Reads the next game.
62  * A derived class implements this function to sequentially read the games
63  * contained into the database.
64  * @param Game&: the Game object where the data will be stored.
65  * @returns
66  * - ERROR_NotFound if there are no more games to be read.
67  * - OK otherwise.
68  */
70 
71  /**
72  * Returns info about the parsing progress.
73  * @returns a pair<size_t, size_t> where first element is the quantity of
74  * data parsed and second one is the total amount of data of the database.
75  */
76  std::pair<size_t, size_t> parseProgress() {
77  return std::pair<size_t, size_t>(1, 1);
78  }
79 
80  /**
81  * Returns the list of errors produced by parseNext() calls.
82  */
83  const char* parseErrors() { return NULL; }
84 
85  /**
86  * Adds a game into the database.
87  * @param Game*: valid pointer to a Game object with the new data.
88  * @returns OK in case of success, an @p errorT code otherwise.
89  */
91 
92  /**
93  * Replaces a game in the database.
94  * @param Game*: valid pointer to a Game object with the new data.
95  * @param gamenumT: valid gamenumT of the game to be replaced.
96  * @returns OK in case of success, an @p errorT code otherwise.
97  */
99 
100 private:
101  errorT addGame(Game* game) final {
102  errorT err = getDerived()->gameAdd(game);
103  if (err != OK)
104  return err;
105 
106  return CodecMemory::addGame(game);
107  }
108 
109  errorT saveGame(Game* game, gamenumT replaced) final {
110  errorT err = getDerived()->gameSave(game, replaced);
111  if (err != OK)
112  return err;
113 
114  return CodecMemory::saveGame(game, replaced);
115  }
116 
117  errorT addGame(const IndexEntry* srcIe, const NameBase* srcNb,
118  const byte* srcData, size_t dataLen) final {
119  ByteBuffer buf(0);
120  buf.ProvideExternal(const_cast<byte*>(srcData), dataLen);
121  Game game;
122  errorT err = game.Decode(&buf, GAME_DECODE_ALL);
123  if (err == OK)
124  err = game.LoadStandardTags(srcIe, srcNb);
125  if (err != OK)
126  return err;
127 
128  err = getDerived()->gameAdd(&game);
129  if (err != OK)
130  return err;
131 
132  return CodecMemory::addGame(srcIe, srcNb, srcData, dataLen);
133  }
134 
135  errorT saveIndexEntry(const IndexEntry&, gamenumT) final {
136  return ERROR_CodecUnsupFeat;
137  }
138 
139  std::pair<errorT, idNumberT> addName(nameT, const char*) final {
140  return std::pair<errorT, idNumberT>(ERROR_CodecUnsupFeat, 0);
141  }
142 
143  /*
144  * Create a memory database, open the non-native database @p filename and
145  * copy all the games into the memory database.
146  */
147  errorT dyn_open(fileModeT fMode, const char* filename,
148  const Progress& progress, Index* idx, NameBase* nb) final {
149  if (filename == 0)
150  return ERROR;
151 
152  errorT err = CodecMemory::dyn_open(FMODE_Memory, filename, progress,
153  idx, nb);
154  if (err != OK)
155  return err;
156 
157  err = getDerived()->open(filename, fMode);
158  if (err != OK)
159  return err;
160 
161  return parseGames(progress, *getDerived(), [&](Game& game) {
162  return this->CodecMemory::addGame(&game);
163  });
164  }
165 
166 public:
167  /*
168  * Given a source database of type CodecProxy<T>, for each game a
169  * corresponding Game object is created and dispatched to @e destFn.
170  */
171  template <typename TProgress, typename TSource, typename TDestFn>
172  static errorT parseGames(const TProgress& progress, TSource& src,
173  TDestFn destFn) {
174 #ifndef MULTITHREADING_OFF
175  auto workTotal = src.parseProgress().second;
176 
177  Game game[4];
178  std::atomic<size_t> workDone{};
179  std::atomic<int8_t> sync[4] = {};
180  enum {sy_free, sy_used, sy_stop};
181 
182  std::thread producer([&]() {
183  uint64_t slot;
184  uint64_t nProduced = 0;
185  while (true) {
186  slot = nProduced % 4;
187  int sy;
188  while (true) { // spinlock if the slot is in use
189  sy = sync[slot].load(std::memory_order_acquire);
190  if (sy == sy_used)
191  std::this_thread::yield();
192  else
193  break;
194  };
195  if (sy == sy_stop)
196  break;
197 
198  if (src.parseNext(game[slot]) == ERROR_NotFound)
199  break;
200 
201  if (++nProduced % 1024 == 0) {
202  workDone.store(src.parseProgress().first,
203  std::memory_order_release);
204  }
205 
206  sync[slot].store(sy_used, std::memory_order_release);
207  }
208  sync[slot].store(sy_stop, std::memory_order_release);
209  });
210 
211  // Consumer
212  errorT err = OK;
213  uint64_t slot;
214  uint64_t nImported = 0;
215  while (true) {
216  slot = nImported % 4;
217  int sy;
218  while (true) { // spinlock if the slot is empty
219  sy = sync[slot].load(std::memory_order_acquire);
220  if (sy == sy_free)
221  std::this_thread::yield();
222  else
223  break;
224  };
225  if (sy == sy_stop)
226  break;
227 
228  if (++nImported % 1024 == 0) {
229  if (!progress.report(workDone.load(std::memory_order_acquire),
230  workTotal)) {
231  err = ERROR_UserCancel;
232  break;
233  }
234  }
235 
236  err = destFn(game[slot]);
237  if (err != OK)
238  break;
239 
240  sync[slot].store(sy_free, std::memory_order_release);
241  }
242  sync[slot].store(sy_stop, std::memory_order_release);
243 
244  producer.join();
245  progress(1, 1, src.parseErrors());
246  return err;
247 
248 #else
249  Game g;
250  errorT err = OK;
251  uint64_t nImported = 0;
252  while (src.parseNext(g) != ERROR_NotFound) {
253  err = destFn(g);
254  if (err != OK)
255  break;
256 
257  if (++nImported % 1024 == 0) {
258  std::pair<size_t, size_t> count = src.parseProgress();
259  if (!progress.report(count.first, count.second)) {
260  err = ERROR_UserCancel;
261  break;
262  }
263  }
264  }
265  progress(1, 1, src.parseErrors());
266  return err;
267 #endif
268  }
269 };
270 
271 #endif
unsigned char byte
Definition: common.h:89
const errorT ERROR_CodecUnsupFeat
Definition: error.h:82
Manages memory databases that do not have associated files.
Definition: codec_memory.h:34
errorT gameSave(Game *, gamenumT)
Replaces a game in the database.
Definition: codec_proxy.h:98
const errorT OK
Definition: error.h:23
errorT parseNext(Game &)
Reads the next game.
Definition: codec_proxy.h:69
errorT addGame(const IndexEntry *srcIe, const NameBase *srcNb, const byte *srcData, size_t dataLen) override
Definition: codec_native.h:53
errorT dyn_open(fileModeT fMode, const char *, const Progress &, Index *idx, NameBase *nb) override
Opens/Creates a database.
Definition: codec_memory.h:68
Definition: misc.h:63
Defines the ICodecDatabase interface, which encapsulates the data representation of databases...
const char * parseErrors()
Returns the list of errors produced by parseNext() calls.
Definition: codec_proxy.h:83
void ProvideExternal(byte *data, size_t length)
Definition: bytebuf.cpp:52
errorT gameAdd(Game *)
Adds a game into the database.
Definition: codec_proxy.h:90
This class stores the database&#39;s names (players, events, sites and rounds).
Definition: namebase.h:33
errorT LoadStandardTags(const IndexEntry *ie, const NameBase *nb)
Definition: game.cpp:2584
const errorT ERROR_UserCancel
Definition: error.h:27
static errorT parseGames(const TProgress &progress, TSource &src, TDestFn destFn)
Definition: codec_proxy.h:172
errorT saveGame(Game *game, gamenumT replaced) override
Definition: codec_native.h:77
std::pair< size_t, size_t > parseProgress()
Returns info about the parsing progress.
Definition: codec_proxy.h:76
Definition: index.h:58
#define GAME_DECODE_ALL
Definition: game.h:128
unsigned short errorT
Definition: error.h:20
Base class for non-native databases.
Definition: codec_proxy.h:48
Definition: game.h:167
unsigned nameT
Definition: common.h:153
errorT open(const char *filename, fileModeT fMode)
Opens/creates a database encoded in a non-native format.
uint gamenumT
Definition: common.h:163
fileModeT
Definition: common.h:136
const errorT ERROR
Definition: error.h:26
const errorT ERROR_NotFound
Definition: error.h:50
Definition: indexentry.h:54
errorT Decode(ByteBuffer *buf, byte flags)
Definition: game.cpp:3549
Implements the CodecMemory class, which represent a memory database.