rod 0.7.1 → 0.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. data/.travis.yml +1 -1
  2. data/README.rdoc +38 -10
  3. data/Rakefile +20 -9
  4. data/changelog.txt +25 -0
  5. data/contributors.txt +1 -0
  6. data/data/backward/0.7.0/_join_element.dat +0 -0
  7. data/data/backward/0.7.0/_polymorphic_join_element.dat +0 -0
  8. data/data/backward/0.7.0/char.dat +0 -0
  9. data/data/backward/0.7.0/database.yml +58 -0
  10. data/data/backward/0.7.0/rod_test__automobile.dat +0 -0
  11. data/data/backward/0.7.0/rod_test__caveman.dat +0 -0
  12. data/data/backward/0.7.0/rod_test__dog.dat +0 -0
  13. data/data/backward/0.7.0/rod_test__test_model.dat +0 -0
  14. data/data/portability/_join_element.dat +0 -0
  15. data/data/portability/_polymorphic_join_element.dat +0 -0
  16. data/data/portability/char.dat +0 -0
  17. data/data/portability/database.yml +49 -0
  18. data/data/portability/rod_test__automobile.dat +0 -0
  19. data/data/portability/rod_test__caveman.dat +0 -0
  20. data/data/portability/rod_test__dog.dat +0 -0
  21. data/data/portability/rod_test__test_model.dat +0 -0
  22. data/features/backward.feature +33 -0
  23. data/features/basic.feature +3 -0
  24. data/features/collection_proxy.feature +95 -0
  25. data/features/flat_indexing.feature +44 -2
  26. data/features/hash_indexing.feature +63 -9
  27. data/features/portability.feature +72 -0
  28. data/features/segmented_indexing.feature +45 -2
  29. data/features/steps/collection_proxy.rb +1 -1
  30. data/features/steps/model.rb +48 -5
  31. data/features/steps/rod.rb +15 -16
  32. data/lib/rod.rb +11 -1
  33. data/lib/rod/abstract_database.rb +52 -42
  34. data/lib/rod/berkeley/collection_proxy.rb +96 -0
  35. data/lib/rod/berkeley/database.rb +337 -0
  36. data/lib/rod/berkeley/environment.rb +209 -0
  37. data/lib/rod/berkeley/sequence.rb +222 -0
  38. data/lib/rod/berkeley/transaction.rb +233 -0
  39. data/lib/rod/collection_proxy.rb +76 -1
  40. data/lib/rod/constants.rb +3 -2
  41. data/lib/rod/database.rb +127 -14
  42. data/lib/rod/index/base.rb +12 -3
  43. data/lib/rod/index/hash_index.rb +295 -70
  44. data/lib/rod/index/segmented_index.rb +3 -0
  45. data/lib/rod/model.rb +154 -531
  46. data/lib/rod/property/base.rb +190 -0
  47. data/lib/rod/property/field.rb +258 -0
  48. data/lib/rod/property/plural_association.rb +145 -0
  49. data/lib/rod/property/singular_association.rb +139 -0
  50. data/rod.gemspec +6 -4
  51. data/spec/berkeley/database.rb +83 -0
  52. data/spec/berkeley/environment.rb +58 -0
  53. data/spec/berkeley/sequence.rb +101 -0
  54. data/spec/berkeley/transaction.rb +92 -0
  55. data/spec/collection_proxy.rb +38 -0
  56. data/spec/database.rb +36 -0
  57. data/spec/model.rb +26 -0
  58. data/spec/property/base.rb +73 -0
  59. data/spec/property/field.rb +244 -0
  60. data/spec/property/plural_association.rb +67 -0
  61. data/spec/property/singular_association.rb +65 -0
  62. data/tests/class_compatibility_create.rb +2 -2
  63. data/tests/eff1_test.rb +1 -1
  64. data/tests/eff2_test.rb +1 -1
  65. data/tests/full_runs.rb +1 -1
  66. data/tests/generate_classes_create.rb +14 -14
  67. data/tests/migration_create.rb +47 -47
  68. data/tests/migration_verify.rb +1 -1
  69. data/tests/missing_class_create.rb +6 -6
  70. data/tests/properties_order_create.rb +4 -4
  71. data/tests/read_on_create.rb +33 -34
  72. data/tests/save_struct.rb +40 -39
  73. data/tests/unit/database.rb +1 -1
  74. data/tests/unit/model_tests.rb +73 -65
  75. metadata +71 -15
  76. data/tests/unit/model.rb +0 -36
@@ -43,16 +43,91 @@ module Rod
43
43
  end
44
44
  end
45
45
 
46
+ # Returns the size of intersection with the other collection proxy.
47
+ # XXX this method assumes that the elements are sorted according to rod_id,
48
+ # the collection is not polymorphic and no elements were added nor deleted.
49
+ def intersection_size(other)
50
+ @database.fast_intersection_size(self.offset,self.size,other.offset,other.size)
51
+ end
52
+
53
+ # Computes a union with the +other+ collection proxy.
54
+ def |(other)
55
+ # So far this optimization works only for monomorphic
56
+ # collection proxies without added elements.
57
+ if @klass && @added.empty?
58
+ my_ids = self.size.times.map do |index|
59
+ id_for(index)
60
+ end.sort
61
+ other_ids = other.size.times.map do |index|
62
+ other.id_for(index)
63
+ end.sort
64
+ ids = []
65
+ last_id = nil
66
+ while(!my_ids.empty?) do
67
+ id = my_ids.shift
68
+ other_ids.shift if other_ids.first == id
69
+ ids << id unless last_id == id
70
+ last_id = id
71
+ end
72
+ while(!other_ids.empty?) do
73
+ id = other_ids.shift
74
+ ids << id unless last_id == id
75
+ last_id = id
76
+ end
77
+ result = CollectionProxy.new(0,@database,0,@klass)
78
+ ids.each{|id| result << [id,@klass]}
79
+ else
80
+ result = self.to_a | other.to_a
81
+ end
82
+ result
83
+ end
84
+
85
+ # Computes an intersection with the +other+ collection proxy.
86
+ def &(other)
87
+ # So far this optimization works only for monomorphic
88
+ # collection proxies without added elements.
89
+ if @klass && @added.empty?
90
+ my_ids = self.size.times.map do |index|
91
+ id_for(index)
92
+ end.sort
93
+ other_ids = other.size.times.map do |index|
94
+ other.id_for(index)
95
+ end.sort
96
+ ids = []
97
+ last_id = nil
98
+ while(!my_ids.empty?) do
99
+ if my_ids.first == other_ids.first
100
+ id = my_ids.shift
101
+ other_ids.shift
102
+ ids << id unless last_id == id
103
+ last_id = id
104
+ elsif my_ids.first < other_ids.first
105
+ my_ids.shift
106
+ else
107
+ other_ids.shift
108
+ end
109
+ end
110
+ result = CollectionProxy.new(0,@database,0,@klass)
111
+ ids.each{|id| result << [id,@klass]}
112
+ else
113
+ result = self.to_a & other.to_a
114
+ end
115
+ result
116
+ end
117
+
46
118
  # Appends element to the end of the collection.
47
119
  def <<(element)
48
120
  if element.nil?
49
121
  pair = [0,NilClass]
50
- else
122
+ elsif element.is_a?(Model)
51
123
  if element.new?
52
124
  pair = [element,element.class]
53
125
  else
54
126
  pair = [element.rod_id,element.class]
55
127
  end
128
+ else
129
+ # Assume we have an array with direct values of rod_id and class.
130
+ pair = element
56
131
  end
57
132
  index = @size
58
133
  @map[index] = @added.size
@@ -1,5 +1,5 @@
1
1
  module Rod
2
- VERSION = "0.7.1"
2
+ VERSION = "0.7.2"
3
3
 
4
4
  # The name of file containing the data base.
5
5
  DATABASE_FILE = "database.yml"
@@ -12,7 +12,8 @@ module Rod
12
12
  :integer => 'long',
13
13
  :float => 'double',
14
14
  :ulong => 'unsigned long',
15
- :object => 'char *'
15
+ :object => 'char *',
16
+ :json => 'char *'
16
17
  }
17
18
 
18
19
  RUBY_TO_C_MAPPING = {
@@ -49,7 +49,7 @@ module Rod
49
49
  | strcpy(path,model_p->path);
50
50
  | strcat(path,"#{klass.path_for_data("")}");
51
51
  | model_p->#{klass.struct_name}_lib_file =
52
- | open(path, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
52
+ | open(path, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
53
53
  | if(model_p->#{klass.struct_name}_lib_file == -1) {
54
54
  | rb_raise(rodException(),"Could not open file for class #{klass} on path %s writing.",path);
55
55
  | }
@@ -92,11 +92,10 @@ module Rod
92
92
  |
93
93
  | // exted the file
94
94
  |
95
- | // increase the pages count by 1
95
+ | // increase the pages count by numer of pages allocated at-once
96
96
  | model_p->#{klass.struct_name}_page_count += ALLOCATED_PAGES;
97
97
  | {
98
98
  | // open the file for writing
99
- | char* #{klass.struct_name}_empty_data;
100
99
  | FILE * #{klass.struct_name}_file =
101
100
  | fdopen(model_p->#{klass.struct_name}_lib_file,"w+");
102
101
  | if(#{klass.struct_name}_file == NULL){
@@ -107,11 +106,11 @@ module Rod
107
106
  | rb_raise(rodException(),"Could not seek to end file for #{klass.struct_name}.");
108
107
  | }
109
108
  | // write empty data at the end
110
- | #{klass.struct_name}_empty_data = calloc(page_size() * ALLOCATED_PAGES,1);
111
- | if(write(model_p->#{klass.struct_name}_lib_file,#{klass.struct_name}_empty_data,
109
+ | if(write(model_p->#{klass.struct_name}_lib_file,model_p->empty_data,
112
110
  | page_size() * ALLOCATED_PAGES) == -1){
113
111
  | rb_raise(rodException(),"Could not write to file for #{klass.struct_name}.");
114
112
  | }
113
+ |
115
114
  | // seek to the beginning
116
115
  | if(fseek(#{klass.struct_name}_file,0,SEEK_SET) == -1){
117
116
  | rb_raise(rodException(),"Could not seek to start file for #{klass.struct_name}.");
@@ -167,6 +166,10 @@ module Rod
167
166
  builder.include '<unistd.h>'
168
167
  builder.include '<errno.h>'
169
168
  builder.include '<sys/mman.h>'
169
+ builder.include '<sys/stat.h>'
170
+ builder.include '<byteswap.h>'
171
+ builder.include '<endian.h>'
172
+ builder.include '<stdint.h>'
170
173
  classes.each do |klass|
171
174
  builder.prefix(klass.typedef_struct)
172
175
  end
@@ -198,19 +201,51 @@ module Rod
198
201
  end.join("\n|\n")}
199
202
  | // the path to the DB
200
203
  | char * path;
204
+ | // chunk written to extend file
205
+ | char * empty_data;
201
206
  |
202
207
  |} #{model_struct};
203
208
  END
204
209
  builder.prefix(str.margin)
205
210
 
211
+ str =<<-END
212
+ |// Deallocates the model struct.
213
+ |void model_struct_free(#{model_struct} * model_p){
214
+ | if(model_p != NULL){
215
+ | if(model_p->path != NULL){
216
+ | // TODO causes segfault
217
+ | //printf("GC %lu %lu\\n",(unsigned long)model_p,
218
+ | // (unsigned long)model_p->path);
219
+ | //free(model_p->path);
220
+ | model_p->path = NULL;
221
+ | }
222
+ | if(model_p->empty_data != NULL){
223
+ | //free(model_p->empty_data);
224
+ | model_p->empty_data = NULL;
225
+ | }
226
+ | }
227
+ | free(model_p);
228
+ |}
229
+ END
230
+ builder.prefix(str.margin)
231
+
232
+
206
233
  #########################################
207
234
  # Join indices
208
235
  #########################################
209
236
  str =<<-END
210
237
  |VALUE _join_element_index(unsigned long element_offset, unsigned long element_index, VALUE handler){
211
238
  | #{model_struct} * model_p;
239
+ | unsigned long result;
240
+ |
212
241
  | Data_Get_Struct(handler,#{model_struct},model_p);
213
- | return ULONG2NUM((model_p->_join_element_table + element_offset + element_index)->offset);
242
+ | result = (model_p->_join_element_table + element_offset + element_index)->offset;
243
+ |#ifdef __BYTE_ORDER
244
+ |# if __BYTE_ORDER == __BIG_ENDIAN
245
+ | result = bswap_64(result);
246
+ |# endif
247
+ |#endif
248
+ | return ULONG2NUM(result);
214
249
  |}
215
250
  END
216
251
  builder.c(str.margin)
@@ -219,9 +254,17 @@ module Rod
219
254
  |VALUE _polymorphic_join_element_index(unsigned long element_offset,
220
255
  | unsigned long element_index, VALUE handler){
221
256
  | #{model_struct} * model_p;
257
+ | unsigned long result;
258
+ |
222
259
  | Data_Get_Struct(handler,#{model_struct},model_p);
223
- | return ULONG2NUM((model_p->_polymorphic_join_element_table +
224
- | element_offset + element_index)->offset);
260
+ | result = (model_p->_polymorphic_join_element_table +
261
+ | element_offset + element_index)->offset;
262
+ |#ifdef __BYTE_ORDER
263
+ |# if __BYTE_ORDER == __BIG_ENDIAN
264
+ | result = bswap_64(result);
265
+ |# endif
266
+ |#endif
267
+ | return ULONG2NUM(result);
225
268
  |}
226
269
  END
227
270
  builder.c(str.margin)
@@ -230,9 +273,17 @@ module Rod
230
273
  |VALUE _polymorphic_join_element_class(unsigned long element_offset,
231
274
  | unsigned long element_index, VALUE handler){
232
275
  | #{model_struct} * model_p;
276
+ | unsigned long result;
277
+ |
233
278
  | Data_Get_Struct(handler,#{model_struct},model_p);
234
- | return ULONG2NUM((model_p->_polymorphic_join_element_table +
235
- | element_offset + element_index)->class);
279
+ | result = (model_p->_polymorphic_join_element_table +
280
+ | element_offset + element_index)->class;
281
+ |#ifdef __BYTE_ORDER
282
+ |# if __BYTE_ORDER == __BIG_ENDIAN
283
+ | result = bswap_64(result);
284
+ |# endif
285
+ |#endif
286
+ | return ULONG2NUM(result);
236
287
  |}
237
288
  END
238
289
  builder.c(str.margin)
@@ -243,12 +294,18 @@ module Rod
243
294
  | VALUE handler){
244
295
  | #{model_struct} * model_p;
245
296
  | _join_element * element_p;
297
+ |
246
298
  | Data_Get_Struct(handler,#{model_struct},model_p);
247
299
  | element_p = model_p->_join_element_table + element_offset + element_index;
248
300
  | if(element_p->index != element_index){
249
301
  | rb_raise(rodException(), "Join element indices are inconsistent: %lu %lu!",
250
302
  | element_index, element_p->index);
251
303
  | }
304
+ |#ifdef __BYTE_ORDER
305
+ |# if __BYTE_ORDER == __BIG_ENDIAN
306
+ | offset = bswap_64(offset);
307
+ |# endif
308
+ |#endif
252
309
  | element_p->offset = offset;
253
310
  |}
254
311
  END
@@ -260,12 +317,19 @@ module Rod
260
317
  | VALUE handler){
261
318
  | #{model_struct} * model_p;
262
319
  | _polymorphic_join_element * element_p;
320
+ |
263
321
  | Data_Get_Struct(handler,#{model_struct},model_p);
264
322
  | element_p = model_p->_polymorphic_join_element_table + element_offset + element_index;
265
323
  | if(element_p->index != element_index){
266
324
  | rb_raise(rodException(), "Polymorphic join element indices are inconsistent: %lu %lu!",
267
325
  | element_index, element_p->index);
268
326
  | }
327
+ |#ifdef __BYTE_ORDER
328
+ |# if __BYTE_ORDER == __BIG_ENDIAN
329
+ | offset = bswap_64(offset);
330
+ | class_id = bswap_64(class_id);
331
+ |# endif
332
+ |#endif
269
333
  | element_p->offset = offset;
270
334
  | element_p->class = class_id;
271
335
  |}
@@ -278,6 +342,7 @@ module Rod
278
342
  | unsigned long index;
279
343
  | #{model_struct} * model_p;
280
344
  | unsigned long result;
345
+ |
281
346
  | Data_Get_Struct(handler,#{model_struct},model_p);
282
347
  | result = model_p->_join_element_count;
283
348
  | for(index = 0; index < size; index++){
@@ -301,6 +366,7 @@ module Rod
301
366
  | unsigned long index;
302
367
  | #{model_struct} * model_p;
303
368
  | unsigned long result;
369
+ |
304
370
  | Data_Get_Struct(handler,#{model_struct},model_p);
305
371
  | result = model_p->_polymorphic_join_element_count;
306
372
  | for(index = 0; index < size; index++){
@@ -321,6 +387,40 @@ module Rod
321
387
  END
322
388
  builder.c(str.margin)
323
389
 
390
+ str =<<-END
391
+ |VALUE _fast_intersection_size(unsigned long first_offset,
392
+ | unsigned long first_length, unsigned long second_offset,
393
+ | unsigned long second_length, VALUE handler){
394
+ | unsigned long i,j,count,v1,v2;
395
+ | #{model_struct} * model_p;
396
+ |
397
+ | i = 0; j = 0; count = 0;
398
+ | Data_Get_Struct(handler,#{model_struct},model_p);
399
+ |
400
+ | while(i < first_length && j < second_length){
401
+ | v1 = (model_p->_join_element_table + first_offset + i)->offset;
402
+ | v2 = (model_p->_join_element_table + second_offset + j)->offset;
403
+ |#ifdef __BYTE_ORDER
404
+ |# if __BYTE_ORDER == __BIG_ENDIAN
405
+ | v1 = bswap_64(v1);
406
+ | v2 = bswap_64(v2);
407
+ |# endif
408
+ |#endif
409
+ | if(v1 < v2){
410
+ | i++;
411
+ | } else {
412
+ | if(v1 > v2){
413
+ | j++;
414
+ | } else {
415
+ | i++; j++; count++;
416
+ | }
417
+ | }
418
+ | }
419
+ | return ULONG2NUM(count);
420
+ |}
421
+ END
422
+ builder.c(str.margin)
423
+
324
424
  #########################################
325
425
  # Strings
326
426
  #########################################
@@ -328,6 +428,7 @@ module Rod
328
428
  |VALUE _read_string(unsigned long length, unsigned long offset, VALUE handler){
329
429
  | #{model_struct} * model_p;
330
430
  | char * str;
431
+ |
331
432
  | Data_Get_Struct(handler,#{model_struct},model_p);
332
433
  | str = model_p->#{StringElement.struct_name}_table + offset;
333
434
  | return rb_str_new(str, length);
@@ -353,6 +454,7 @@ module Rod
353
454
  | long length_left = length;
354
455
  | // see the routine description above.
355
456
  | VALUE result;
457
+ |
356
458
  | // get the structure
357
459
  | Data_Get_Struct(handler,#{model_struct},model_p);
358
460
  | // first free byte in current page
@@ -407,9 +509,9 @@ module Rod
407
509
  str =<<-END
408
510
  |// Store the object in the database.
409
511
  |void _store_#{klass.struct_name}(VALUE object, VALUE handler){
410
- |
411
512
  | #{model_struct} * model_p;
412
513
  | #{klass.struct_name} * struct_p;
514
+ |
413
515
  | Data_Get_Struct(handler,#{model_struct},model_p);
414
516
  | if((model_p->#{klass.struct_name}_count+1) * sizeof(#{klass.struct_name}) >=
415
517
  | model_p->#{klass.struct_name}_page_count * page_size()){
@@ -436,17 +538,22 @@ module Rod
436
538
  |VALUE _init_handler(char * dir_path){
437
539
  | #{model_struct} * model_p;
438
540
  | VALUE cClass;
439
- | model_p = ALLOC(#{model_struct});
440
541
  |
542
+ | model_p = ALLOC(#{model_struct});
441
543
  | #{init_structs(classes)}
442
544
  |
443
545
  | // set dir path
444
546
  | model_p->path = malloc(sizeof(char)*(strlen(dir_path)+1));
445
547
  | strcpy(model_p->path,dir_path);
446
548
  |
549
+ | // initialize empty data written when extending file
550
+ | model_p->empty_data = calloc(page_size() * ALLOCATED_PAGES,1);
551
+ |
447
552
  | //create the wrapping object
448
553
  | cClass = rb_define_class("#{model_struct_name(path).camelcase(true)}",
449
554
  | rb_cObject);
555
+ | // TODO #225
556
+ | //return Data_Wrap_Struct(cClass, 0, model_struct_free, model_p);
450
557
  | return Data_Wrap_Struct(cClass, 0, free, model_p);
451
558
  |}
452
559
  END
@@ -472,6 +579,7 @@ module Rod
472
579
  str =<<-END
473
580
  |void _open(VALUE handler){
474
581
  | #{model_struct} * model_p;
582
+ |
475
583
  | Data_Get_Struct(handler,#{model_struct},model_p);
476
584
  |
477
585
  | \n#{classes.map do |klass|
@@ -502,6 +610,7 @@ module Rod
502
610
  |// if +classes+ are Qnil, the DB was open in readonly mode.
503
611
  |void _close(VALUE handler){
504
612
  | #{model_struct} * model_p;
613
+ |
505
614
  | Data_Get_Struct(handler,#{model_struct},model_p);
506
615
  |
507
616
  | \n#{classes.map do |klass|
@@ -528,13 +637,13 @@ module Rod
528
637
  str = <<-END
529
638
  |void _print_layout(VALUE handler){
530
639
  | #{model_struct} * model_p;
640
+ |
531
641
  | Data_Get_Struct(handler,#{model_struct},model_p);
532
642
  | printf("============= Data layout START =============\\n");
533
643
  | \n#{classes.map do |klass|
534
644
  str =<<-SUBEND
535
645
  | printf("-- #{klass} --\\n");
536
646
  | printf("Size of #{klass.struct_name} %lu\\n",(unsigned long)sizeof(#{klass.struct_name}));
537
- | \n#{klass.layout}
538
647
  | printf("Page count: %lu, count %lu, pointer: %lx\\n",
539
648
  | model_p->#{klass.struct_name}_page_count,
540
649
  | model_p->#{klass.struct_name}_count,
@@ -580,6 +689,7 @@ module Rod
580
689
  str =<<-END
581
690
  |#{result_type} _#{name}(VALUE handler){
582
691
  | #{model_struct} * model_p;
692
+ |
583
693
  | Data_Get_Struct(handler,#{model_struct},model_p);
584
694
  | return model_p->#{name};
585
695
  |}
@@ -592,6 +702,7 @@ module Rod
592
702
  str =<<-END
593
703
  |void _#{name}_equals(VALUE handler,#{arg_type} value){
594
704
  | #{model_struct} * model_p;
705
+ |
595
706
  | Data_Get_Struct(handler,#{model_struct},model_p);
596
707
  | model_p->#{name} = value;
597
708
  |}
@@ -602,7 +713,9 @@ module Rod
602
713
  def self.rod_exception
603
714
  str =<<-END
604
715
  |VALUE rodException(){
605
- | VALUE klass = rb_const_get(rb_cObject, rb_intern("Rod"));
716
+ | VALUE klass;
717
+ |
718
+ | klass = rb_const_get(rb_cObject, rb_intern("Rod"));
606
719
  | klass = rb_const_get(klass, rb_intern("DatabaseError"));
607
720
  | return klass;
608
721
  |}
@@ -42,9 +42,9 @@ module Rod
42
42
  proxy = get(key)
43
43
  end
44
44
  if proxy.nil?
45
- proxy = CollectionProxy.new(0,@klass.database,0,@klass)
45
+ proxy = empty_collection_proxy(key)
46
46
  else
47
- unless proxy.is_a?(CollectionProxy)
47
+ if Array === proxy
48
48
  offset, count = proxy
49
49
  proxy = CollectionProxy.new(count,@klass.database,offset,@klass)
50
50
  end
@@ -61,6 +61,7 @@ module Rod
61
61
  # Copies the values from +index+ to this index.
62
62
  def copy(index)
63
63
  index.each.with_index do |key_value,position|
64
+ # TODO #206 this doesn't work for hash
64
65
  self.set(key_value[0],key_value[1])
65
66
  # TODO #182 implement size for index
66
67
  # report_progress(position,index.size) if $ROD_DEBUG
@@ -85,6 +86,14 @@ module Rod
85
86
  "#{self.class}@#{@path}"
86
87
  end
87
88
 
89
+ protected
90
+
91
+ # Returns an empty collection proxy. Might be changed
92
+ # in subclasses to provie index-specific collection proxies.
93
+ def empty_collection_proxy(key)
94
+ CollectionProxy.new(0,@klass.database,0,@klass)
95
+ end
96
+
88
97
  class << self
89
98
  # Creats the proper instance of Index or one of its sublcasses.
90
99
  # The +path+ is the path were the index is stored, while +index+ is the previous index instance.
@@ -105,7 +114,7 @@ module Rod
105
114
  warn("Index type 'true' is deprecated. It will be removed in ROD 0.8.0")
106
115
  FlatIndex.new(path,klass,options)
107
116
  else
108
- raise RodException.new("Invalid index type #{type}")
117
+ raise RodException.new("Invalid index type '#{type}'")
109
118
  end
110
119
  end
111
120
  end