Class: KBEngine

Inherits:
Object
  • Object
show all
Includes:
DRb::DRbUndumped
Defined in:
lib/og/store/kirby/kirbybase.rb

Overview


KBEngine


Constant Summary collapse

EN_STR =
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' + \
'0123456789.+-,$:|&;_ '
EN_STR_LEN =
EN_STR.length
EN_KEY1 =

*** DO NOT CHANGE ***

")2VER8GE\"87-E\n"
EN_KEY =
EN_KEY_LEN =
EN_KEY.length
ENCODE_RE =

Regular expression used to determine if field needs to be encoded.

/&|\n|\r|\032|\|/

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(db) ⇒ KBEngine

Returns a new instance of KBEngine.



256
257
258
259
260
# File 'lib/og/store/kirby/kirbybase.rb', line 256

def initialize(db)
    @db = db
    # This hash will hold the table locks if in client/server mode.
    @mutex_hash = {} if @db.server?
end

Class Method Details

.create_called_from_database_instance(db) ⇒ Object



252
253
254
# File 'lib/og/store/kirby/kirbybase.rb', line 252

def KBEngine.create_called_from_database_instance(db)
    return new(db)
end

Instance Method Details

#delete_records(table, recs) ⇒ Object


delete_records




480
481
482
483
484
485
486
487
488
489
490
491
492
# File 'lib/og/store/kirby/kirbybase.rb', line 480

def delete_records(table, recs)
    with_write_locked_table(table) do |fptr|
        recs.each do |rec|
            # Go to offset within the file where the record is and 
            # replace it with all spaces.
            write_record(table, fptr, rec.fpos, ' ' * rec.line_length)
            incr_del_ctr(table, fptr)
        end

        # Return the number of records deleted.
        return recs.size
    end
end

#delete_table(tablename) ⇒ Object


delete_table


++ Delete a table.

tablename

Symbol or string of table name.



340
341
342
343
344
345
# File 'lib/og/store/kirby/kirbybase.rb', line 340

def delete_table(tablename)
    with_write_lock(tablename) do
        File.delete(File.join(@db.path, tablename.to_s + @db.ext))
        return true
    end
end

#get_header_vars(table) ⇒ Object


get_header_vars


++ Returns array containing first line of file.

table

Table instance.



367
368
369
370
371
372
373
374
375
376
377
378
# File 'lib/og/store/kirby/kirbybase.rb', line 367

def get_header_vars(table)
    with_table(table) do |fptr|
        line = get_header_record(table, fptr)

        last_rec_no, del_ctr, record_class, *flds = line.split('|')
        field_names = flds.collect { |x| x.split(':')[0].to_sym }
        field_types = flds.collect { |x| x.split(':')[1].to_sym }

        return [table.encrypted?, last_rec_no.to_i, del_ctr.to_i, 
         record_class, field_names, field_types]
    end
end

#get_recs(table) ⇒ Object


get_recs


++ Return array of all table records (arrays).

table

Table instance.



388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
# File 'lib/og/store/kirby/kirbybase.rb', line 388

def get_recs(table)
    encrypted = table.encrypted?
    recs = []
    
    with_table(table) do |fptr|
        begin
            # Skip header rec.
            fptr.readline

            # Loop through table.
            while true
                # Record current position in table.  Then read first
                # detail record.
                fpos = fptr.tell
                line = fptr.readline
              
                line = unencrypt_str(line) if encrypted
                line.strip!

                # If blank line (i.e. 'deleted'), skip it.
                next if line == ''
           
                # Split the line up into fields.
                rec = line.split('|', -1)     
                rec << fpos << line.length
                recs << rec
            end        
        # Here's how we break out of the loop...
        rescue EOFError
        end
        return recs
    end
end

#get_total_recs(table) ⇒ Object


get_total_recs


++ Return total number of non-deleted records in table.

table

Table instance.



355
356
357
# File 'lib/og/store/kirby/kirbybase.rb', line 355

def get_total_recs(table)
    return get_recs(table).size
end

#insert_record(table, rec) ⇒ Object


insert_record




426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
# File 'lib/og/store/kirby/kirbybase.rb', line 426

def insert_record(table, rec)
    with_write_locked_table(table) do |fptr|
        # Auto-increment the record number field.
        rec_no = incr_rec_no_ctr(table, fptr)

       # Insert the newly created record number value at the beginning
       # of the field values.
       rec[0] = rec_no

       # Encode any special characters (like newlines) before writing
       # out the record.
       write_record(table, fptr, 'end', rec.collect { |r| encode_str(r) 
       }.join('|'))

       # Return the record number of the newly created record.
       return rec_no
    end
end

#new_table(name, field_defs, encrypt, record_class) ⇒ Object


new_table


++ Create physical file holding table. This table should not be directly called in your application, but only called by #create_table.

name

Symbol or string of table name.

field_defs

List of field names (Symbols) and field types (Symbols)

encrypt

true/false specifying whether table should be encrypted.

record_class

Class or String specifying the user create class that



301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
# File 'lib/og/store/kirby/kirbybase.rb', line 301

def new_table(name, field_defs, encrypt, record_class)   
    # Can't create a table that already exists!
    raise "Table #{name.to_s} already exists!" if table_exists?(name)

    raise "Must have a field type for each field name" \
     unless field_defs.size.remainder(2) == 0
      
    temp_field_defs = []
    (0...field_defs.size).step(2) { |x|
        raise "Invalid field type: #{field_defs[x+1]}" unless \
         KBTable.valid_field_type?(field_defs[x+1])
        temp_field_defs << \
         "#{field_defs[x].to_s}:#{field_defs[x+1]}"
    }
    
    # Header rec consists of last record no. used, delete count, and
    # all field names/types.  Here, I am inserting the 'recno' field
    # at the beginning of the fields.
    header_rec = ['000000', '000000', record_class, 'recno:Integer', 
     temp_field_defs].join('|')
        
    header_rec = 'Z' + encrypt_str(header_rec) if encrypt
            
    begin
        fptr = open(File.join(@db.path, name.to_s + @db.ext), 'w')
        fptr.write(header_rec + "\n")
    ensure
        fptr.close    
    end
end

#pack_table(table) ⇒ Object


pack_table




498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
# File 'lib/og/store/kirby/kirbybase.rb', line 498

def pack_table(table)
    with_write_lock(table) do
        fptr = open(table.filename, 'r')
        new_fptr = open(table.filename+'temp', 'w')
        
        line = fptr.readline.chomp
        # Reset the delete counter in the header rec to 0.
        if line[0..0] == 'Z'
            header_rec = unencrypt_str(line[1..-1]).split('|')
            header_rec[1] = '000000'
            new_fptr.write('Z' + encrypt_str(header_rec.join('|')) + 
             "\n")
        else
            header_rec = line.split('|')
            header_rec[1] = '000000'
            new_fptr.write(header_rec.join('|') + "\n")
        end        

        lines_deleted = 0

        begin
            while true
                line = fptr.readline
         
                if table.encrypted?
                    temp_line = unencrypt_str(line)
                else
                    temp_line = line    
                end
       
                if temp_line.strip == ''
                    lines_deleted += 1
                else
                    new_fptr.write(line)
                end
            end
        # Here's how we break out of the loop...
        rescue EOFError
        end

        # Close the table and release the write lock.
        fptr.close
        new_fptr.close
        File.delete(table.filename)
        FileUtils.mv(table.filename+'temp', table.filename)

        # Return the number of deleted records that were removed.
        return lines_deleted
    end
end

#table_exists?(tablename) ⇒ Boolean


table_exists?


++ Return true if table exists.

tablename

Symbol or string of table name.

Returns:

  • (Boolean)


270
271
272
# File 'lib/og/store/kirby/kirbybase.rb', line 270

def table_exists?(tablename)
    return File.exists?(File.join(@db.path, tablename.to_s + @db.ext))
end

#tablesObject


tables


++ Return an array containing the names of all tables in this database.



280
281
282
283
284
285
286
287
# File 'lib/og/store/kirby/kirbybase.rb', line 280

def tables
    list = []
    Dir.foreach(@db.path) { |filename|
        list << File.basename(filename, '.*').to_sym if \
         filename =~ Regexp.new(@db.ext)
    }
    return list
end

#update_records(table, recs) ⇒ Object


update_records




449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
# File 'lib/og/store/kirby/kirbybase.rb', line 449

def update_records(table, recs)
    with_write_locked_table(table) do |fptr|
        recs.each do |rec|
            line = rec[:rec].collect { |r| encode_str(r) }.join('|')

            # This doesn't actually 'delete' the line, it just
            # makes it all spaces.  That way, if the updated
            # record is the same or less length than the old
            # record, we can write the record back into the
            # same spot.  If the updated record is greater than
            # the old record, we will leave the now spaced-out
            # line and write the updated record at the end of
            # the file.
            write_record(table, fptr, rec[:fpos], 
             ' ' * rec[:line_length])
            if line.length > rec[:line_length]
                write_record(table, fptr, 'end', line)
                incr_del_ctr(table, fptr)
            else
                write_record(table, fptr, rec[:fpos], line)
            end
        end
        # Return the number of records updated.
        return recs.size
    end
end