~ubuntu-branches/ubuntu/saucy/steam/saucy-backports

« back to all changes in this revision

Viewing changes to server/kernel/db_file.pike

  • Committer: Package Import Robot
  • Author(s): Felix Geyer
  • Date: 2013-10-29 19:51:18 UTC
  • mfrom: (0.2.4) (3.2.1 trusty-proposed)
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: package-import@ubuntu.com-20131029195118-b9bxciz5hwx5z459
Tags: 1:1.0.0.39-2ubuntu1
Add an epoch to the version number as there was an unrelated steam package
in the archive with a higher version number.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (C) 2000-2004  Thomas Bopp, Thorsten Hampel, Ludger Merkens
2
 
 *
3
 
 *  This program is free software; you can redistribute it and/or modify
4
 
 *  it under the terms of the GNU General Public License as published by
5
 
 *  the Free Software Foundation; either version 2 of the License, or
6
 
 *  (at your option) any later version.
7
 
 *
8
 
 *  This program is distributed in the hope that it will be useful,
9
 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
 
 *  GNU General Public License for more details.
12
 
 *
13
 
 *  You should have received a copy of the GNU General Public License
14
 
 *  along with this program; if not, write to the Free Software
15
 
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16
 
 * 
17
 
 * $Id: db_file.pike,v 1.1.1.1 2006/03/27 12:40:10 exodusd Exp $
18
 
 */
19
 
 
20
 
constant cvs_version="$Id: db_file.pike,v 1.1.1.1 2006/03/27 12:40:10 exodusd Exp $";
21
 
 
22
 
 
23
 
/*
24
 
 * /kernel/db_file
25
 
 * this is the database file emulation, which stores a binary file
26
 
 * in a sequence of 64k blobs in a SQL database.
27
 
 */
28
 
 
29
 
#include <macros.h>
30
 
 
31
 
private int                         iID;
32
 
private static int          iNextRecNbr;     /* last current read */
33
 
private static int             iCurrPos;      /* current position */
34
 
private static int           iMaxRecNbr; /*  last rec_order block */
35
 
private static int           iMinRecNbr; /* first rec_order block */
36
 
private static string             sMode;            /* read/write */
37
 
private static string       sReadBuf="";    
38
 
private static string      sWriteBuf="";
39
 
private static int         iFileSize=-1; /* not set otherwise >=0 */
40
 
private static object        readRecord;
41
 
private static int        iStopReader=0;
42
 
private static Thread.MutexKey  mReader;
43
 
private static int          iPrefetch=1;
44
 
private function                    fdb;
45
 
private static int          iLastAccess;
46
 
 
47
 
array get_database_handle(int id)
48
 
{
49
 
    return _Database->connect_db_file(id);
50
 
}
51
 
 
52
 
void create(int ID, string mode) {
53
 
    open(ID, mode);
54
 
}
55
 
 
56
 
#define READ_ONCE 100
57
 
 
58
 
/**
59
 
 * open a database content with given ID, if ID 0 is given a new ID
60
 
 * will be generated.
61
 
 *
62
 
 * @param   int ID      - (an Content ID | 0)
63
 
 * @param   string mode - 
64
 
 *               'r'  open file for reading  
65
 
 *               'w'  open file for writing  
66
 
 *               'a'  open file for append (use with 'w')  
67
 
 *               't'  truncate file at open (use with 'w')  
68
 
 *               'c'  create file if it doesn't exist (use with 'w')
69
 
 *                   'x'  fail if file already exist (use with 'c')
70
 
 *
71
 
 *          How must _always_ contain exactly one 'r' or 'w'.
72
 
 *          if no ID is given, mode 'wc' is assumed
73
 
 *          'w' assumes 'a' unless 't'
74
 
 *          't' overrules 'a'
75
 
 *
76
 
 * @return  On success the ID (>1) -- 0 otherwise
77
 
 * @see     Stdio.file
78
 
 * @author Ludger Merkens 
79
 
 */
80
 
 
81
 
int open(int ID, string mode) {
82
 
    sMode = mode;
83
 
    iID = ID;
84
 
    Sql.sql_result odbResult;    //     db = iID >> OID_BITS;
85
 
    
86
 
    if (!iID)
87
 
        sMode = "wc";
88
 
    [fdb, iID] = get_database_handle(iID);
89
 
 
90
 
    //    LOG("opened db_file for mode "+sMode+" with id "+iID);
91
 
 
92
 
    iCurrPos = 0;
93
 
    if (search(sMode, "r")!=-1)
94
 
    {
95
 
        odbResult =
96
 
            fdb()->big_query("select min(rec_order), max(rec_order) "+
97
 
                             "from doc_data where "+
98
 
                             "doc_id ="+iID);
99
 
        array res= odbResult->fetch_row();
100
 
        iMinRecNbr= (int) res[0];
101
 
        iMaxRecNbr= (int) res[1]; // both 0 if FileNotFound
102
 
        iNextRecNbr = iMinRecNbr;
103
 
        
104
 
        odbResult =
105
 
            fdb()->big_query("select rec_data from doc_data where doc_id="+iID+
106
 
                             " and rec_order="+iMinRecNbr);
107
 
        if (odbResult->num_rows()==1)
108
 
        {
109
 
            [sReadBuf] = odbResult->fetch_row();
110
 
            if (strlen(sReadBuf)<MAX_BUFLEN) // we got the complete file
111
 
                iFileSize = strlen(sReadBuf);
112
 
            else
113
 
                iPrefetch = 1;               // otherwise assume prefetching
114
 
            iNextRecNbr++;
115
 
        }
116
 
        
117
 
        return ID;
118
 
    }
119
 
    if (search(sMode, "w")==-1) // neither read nor write mode given
120
 
        return 0;
121
 
 
122
 
    // Append to database, calculate next RecNbr
123
 
    odbResult = fdb()->big_query("select max(rec_order) from "+
124
 
                                "doc_data where doc_id = "+iID);
125
 
    if (!objectp(odbResult))
126
 
        iNextRecNbr = -1;
127
 
    else
128
 
    {
129
 
        iNextRecNbr = ((int) odbResult->fetch_row()[0])+1;
130
 
    }
131
 
    if (search(sMode, "c")!=-1)
132
 
    {
133
 
        if ((search(sMode,"x")!=-1) && (iNextRecNbr != -1))
134
 
            return 0;
135
 
            
136
 
        if (iNextRecNbr == -1)
137
 
            iNextRecNbr = 0;
138
 
    }
139
 
 
140
 
    if (search(sMode, "t")!=-1)
141
 
    {
142
 
        if (iNextRecNbr!=-1)
143
 
            fdb()->big_query("delete from doc_data where doc_id = "+
144
 
                            iID);
145
 
        iNextRecNbr = 1;
146
 
    }
147
 
 
148
 
    if (iNextRecNbr == -1) // 'w' without 'c' but file doesn't exist
149
 
        return 0;
150
 
 
151
 
    return iID;
152
 
}
153
 
    
154
 
private static void write_buf(string data) {
155
 
    //        LOG_DB("write_buf: "+strlen(data)+" RecNbr:"+iNextRecNbr);
156
 
    string line = "insert into doc_data values('"+
157
 
        fdb()->quote(data)+"', "+ iID +", "+iNextRecNbr+")";
158
 
    mixed c = catch{fdb()->big_query(line);};
159
 
    if (c) {
160
 
        LOG_DB("write_buf: "+c[0]+"\n"+master()->describe_backtrace(c[1]));
161
 
    }
162
 
    iMaxRecNbr=iNextRecNbr;
163
 
    iNextRecNbr++;
164
 
    iFileSize=-1;
165
 
}
166
 
        
167
 
int close() {
168
 
    // werror("closing db_file"+iID+" from mode "+sMode);
169
 
    if (search(sMode,"w")!=-1)
170
 
    {
171
 
        if (strlen(sWriteBuf) > 0)
172
 
            write_buf(sWriteBuf);
173
 
        iFileSize = (((iMaxRecNbr - iMinRecNbr)-1) * MAX_BUFLEN) +
174
 
            strlen(sWriteBuf);
175
 
    }
176
 
    stop_reader();
177
 
}
178
 
 
179
 
void destroy() {
180
 
    close();
181
 
}
182
 
 
183
 
static int sendByte = 0;    
184
 
 
185
 
int get_last_access() { return iLastAccess; }
186
 
 
187
 
static void check_status(object record)
188
 
{
189
 
    object mlock;
190
 
    mlock = record->fullMutex->lock();
191
 
    if ( functionp(record->restore) ) {
192
 
      record->restore(record);
193
 
      record->restore = 0;
194
 
    }
195
 
    destruct(mlock);
196
 
 
197
 
}
198
 
 
199
 
string read(int|void nbytes, int|void notall) 
200
 
{
201
 
    array(string) lbuf = ({});
202
 
    mixed                line;
203
 
    int               iSumLen;
204
 
    Sql.sql_result    odbData;
205
 
 
206
 
 
207
 
    if ( search(sMode,"r") == -1 )
208
 
      return 0;
209
 
 
210
 
    iLastAccess = time();
211
 
 
212
 
    
213
 
    if (!nbytes)               // all the stuff -> no queuing
214
 
    {
215
 
      odbData = fdb()->big_query("select rec_data from doc_data "+
216
 
                                 "where doc_id="+iID+
217
 
                                 " order by rec_order");
218
 
      while (line = odbData->fetch_row())
219
 
        lbuf += ({ line[0] });
220
 
      return lbuf * "";
221
 
    } 
222
 
    else if ( !objectp(readRecord) && 
223
 
              (iFileSize == -1 || iFileSize> MAX_BUFLEN ) && iPrefetch ) 
224
 
    {
225
 
        readRecord = _Database->read_from_database(iID, 
226
 
                                                   iNextRecNbr, 
227
 
                                                   iMaxRecNbr, 
228
 
                                                   this_object());
229
 
    }
230
 
    
231
 
    iSumLen = strlen(sReadBuf);
232
 
    lbuf = ({ sReadBuf });
233
 
    line = "";
234
 
    while ( iSumLen < nbytes && stringp(line) )
235
 
    {
236
 
        if  ( readRecord ) // check for Prefetched Content
237
 
        {
238
 
          check_status(readRecord);
239
 
          line = readRecord->contFifo->read();
240
 
        }
241
 
        else if (iNextRecNbr < iMaxRecNbr) // large files + seek
242
 
        {
243
 
            iPrefetch = 1;
244
 
            readRecord = _Database->read_from_database(iID,
245
 
                                                       iNextRecNbr,
246
 
                                                       iMaxRecNbr, 
247
 
                                                       this_object());
248
 
            check_status(readRecord);
249
 
            line = readRecord->contFifo->read();        
250
 
        }
251
 
        else
252
 
            line = 0; // small files
253
 
        
254
 
        if ( stringp(line) )
255
 
        {
256
 
            lbuf += ({ line });
257
 
            iSumLen += strlen(line);
258
 
        }
259
 
        else {
260
 
          sMode = "";
261
 
        }
262
 
        if ( notall)
263
 
            break;
264
 
    }
265
 
    sReadBuf = lbuf * "";
266
 
    
267
 
    if (!strlen(sReadBuf))
268
 
        return 0;
269
 
 
270
 
    if (strlen(sReadBuf) <= nbytes)  // eof or notall
271
 
    {
272
 
        line = sReadBuf;
273
 
        sReadBuf = "";
274
 
        iCurrPos += strlen(line);
275
 
        sendByte += strlen(line);
276
 
 
277
 
        return line;
278
 
    }
279
 
    line = sReadBuf[..nbytes-1];
280
 
    sReadBuf = sReadBuf[nbytes..];
281
 
    iCurrPos += strlen(line);
282
 
    sendByte += strlen(line);
283
 
    return line;
284
 
}
285
 
 
286
 
int write(string data) {
287
 
    int iWritten = 0;
288
 
 
289
 
    if (search(sMode, "w")==-1)
290
 
        return -1;
291
 
 
292
 
    sWriteBuf += data;
293
 
    while (strlen(sWriteBuf) >= MAX_BUFLEN)
294
 
    {
295
 
        write_buf(sWriteBuf[..MAX_BUFLEN-1]);
296
 
        sWriteBuf = sWriteBuf[MAX_BUFLEN..];
297
 
        iWritten += MAX_BUFLEN;
298
 
    }
299
 
    iCurrPos += iWritten;
300
 
    return iWritten;
301
 
}
302
 
 
303
 
object stat()
304
 
{
305
 
    object s = Stdio.Stat();
306
 
    s->size = sizeof();
307
 
    return s;
308
 
}
309
 
 
310
 
int sizeof() {
311
 
 
312
 
    if (iFileSize!=-1)  // already calculated
313
 
        return iFileSize;
314
 
        
315
 
    Sql.sql_result res;
316
 
    int  iLastChunkLen;
317
 
 
318
 
    if (search(sMode, "w")!=-1)
319
 
    {
320
 
        int erg;
321
 
        iLastChunkLen = strlen(sWriteBuf);
322
 
 
323
 
        erg = ((iMaxRecNbr-iMinRecNbr) * MAX_BUFLEN) + iLastChunkLen;
324
 
        return erg;
325
 
    }
326
 
    else
327
 
    {
328
 
        res = fdb()->big_query(
329
 
            "select length(rec_data) from doc_data "+
330
 
            "where doc_id ="+iID+" and rec_order="+iMaxRecNbr);
331
 
    
332
 
        mixed row = res->fetch_row();
333
 
        if ( arrayp(row) )
334
 
          iLastChunkLen = ((int)row[0]);
335
 
        else
336
 
          iLastChunkLen = 0;
337
 
    }
338
 
 
339
 
    iFileSize = ((iMaxRecNbr-iMinRecNbr) * MAX_BUFLEN) + iLastChunkLen;
340
 
    return iFileSize;
341
 
}
342
 
 
343
 
int dbContID() {
344
 
    return iID;
345
 
}
346
 
 
347
 
 
348
 
private static void stop_reader()
349
 
{
350
 
  if ( objectp(readRecord) ) {
351
 
    //werror("Trying to stop read operation on "+ readRecord->iID+"\n");
352
 
    readRecord->stopRead = 1;
353
 
  }
354
 
}
355
 
 
356
 
/**
357
 
 * seek in an already open database content to a specific offset
358
 
 * If pos is negative it will be relative to the start of the file,
359
 
 * otherwise it will be an absolute offset from the start of the file.
360
 
 * 
361
 
 * @param    int pos - the position as described above
362
 
 * @return   The absolute new offset or -1 on failure
363
 
 * @see      tell
364
 
 *
365
 
 * @caveats  The old syntax from Stdio.File->seek with blocks is not
366
 
 *           supported
367
 
 */
368
 
 
369
 
int seek(int pos)
370
 
{
371
 
    int SeekBlock;
372
 
    int SeekPos;
373
 
    Sql.sql_result odbResult;
374
 
    iPrefetch = 0;
375
 
 
376
 
    //werror("Seek(%d)\n", pos);
377
 
 
378
 
    if (pos<0)
379
 
        SeekPos = iCurrPos-SeekPos;
380
 
    else
381
 
        SeekPos = pos;
382
 
    SeekBlock = SeekPos / MAX_BUFLEN;
383
 
    SeekBlock += iMinRecNbr;
384
 
 
385
 
    stop_reader();  // discard prefetch and stop read_thread
386
 
    odbResult = fdb()->big_query("select rec_data from doc_data where doc_id="+
387
 
                                 iID+" and rec_order="+SeekBlock);
388
 
    if (odbResult->num_rows()==1)
389
 
    {
390
 
        [sReadBuf] = odbResult->fetch_row();
391
 
        sReadBuf = sReadBuf[(SeekPos % iMinRecNbr)..];
392
 
        iCurrPos = SeekPos;
393
 
        iNextRecNbr = SeekBlock+1;
394
 
        return iCurrPos;
395
 
    }
396
 
    return -1;
397
 
}
398
 
 
399
 
/**
400
 
 * tell the current offset in an already open database content
401
 
 * @return   The absolute offset
402
 
 */
403
 
 
404
 
int tell()
405
 
{
406
 
    return iCurrPos;
407
 
}
408
 
 
409
 
string _sprintf()
410
 
{
411
 
    return "kernel/db_file(id="+iID+", stopped="+iStopReader+")";
412
 
}